Skip to content

Commit 4d93057

Browse files
authored
Merge pull request #147 from giomf/main
Add alarm 0003 & 0004
2 parents d53199a + 24f977f commit 4d93057

File tree

14 files changed

+263
-6
lines changed

14 files changed

+263
-6
lines changed

assets/img/einsaetze/2025/0003.jpg

2.78 MB
Loading

assets/img/einsaetze/2025/0004.jpg

2.57 MB
Loading

content.py

Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,75 @@
3131
_INDEX_TEMPLATE_SHORTCODE_SNIPPET = '\n{{< image src="img01" >}}'
3232

3333

34+
def get_latest_year() -> str:
35+
"""
36+
Get the latest year from the content directory.
37+
38+
Returns:
39+
str: The latest year found in the content directory, or the current year if none found
40+
"""
41+
years = []
42+
for path in _TARGET_BASE_PATH.iterdir():
43+
if path.is_dir() and path.name.isdigit():
44+
years.append(path.name)
45+
46+
if not years:
47+
return str(datetime.now().year)
48+
49+
return max(years)
50+
51+
52+
def get_next_id(year: str) -> str:
53+
"""
54+
Get the next available ID for a given year.
55+
56+
Args:
57+
year (str): The year to check for existing IDs
58+
59+
Returns:
60+
str: The next available ID formatted as a 4-digit string
61+
"""
62+
year_path = _TARGET_BASE_PATH.joinpath(year)
63+
if not year_path.exists():
64+
return "0000"
65+
66+
ids = []
67+
for path in year_path.iterdir():
68+
if path.is_dir() and path.name.isdigit():
69+
ids.append(int(path.name))
70+
71+
if not ids:
72+
return "0000"
73+
74+
return f"{max(ids) + 1:04d}"
75+
76+
3477
def parse_arguments():
78+
"""
79+
Parse command line arguments for the script.
80+
81+
Sets up the argument parser with three subcommands:
82+
- create: Creates a new content page with either a template or from input
83+
- remove: Removes an existing content page
84+
- print: Prints the content of an existing page
85+
86+
Returns:
87+
argparse.Namespace: The parsed command line arguments
88+
"""
3589
parser = argparse.ArgumentParser(description="Parse arguments for template, name, and year.")
3690
subparsers = parser.add_subparsers(dest='command', required=True, help="Subcommands")
3791

92+
# Get default values for create command
93+
default_year = get_latest_year()
94+
default_id = get_next_id(default_year)
95+
3896
remove_parser = subparsers.add_parser('remove', help='Removes a content page')
3997
remove_parser.add_argument('--year', type=str, required=True, help='The year')
4098
remove_parser.add_argument('--id', type=str, required=True, help='The content id')
4199

42100
create_parser = subparsers.add_parser('create', help='Creates a content page')
43-
create_parser.add_argument('--year', type=str, required=True, help='The year')
44-
create_parser.add_argument('--id', type=str, required=True, help='The content id')
101+
create_parser.add_argument('--year', type=str, default=default_year, help=f'The year (default: {default_year})')
102+
create_parser.add_argument('--id', type=str, default=default_id, help=f'The content id (default: {default_id})')
45103
create_parser_group = create_parser.add_mutually_exclusive_group(required=True)
46104
create_parser_group.add_argument('--template', action='store_true')
47105
create_parser_group.add_argument('--input', type=str)
@@ -56,6 +114,18 @@ def parse_arguments():
56114

57115

58116
def create_base_paths(year: str, index: str):
117+
"""
118+
Create the base directory structure for a new content page.
119+
120+
Creates the content directory and an img subdirectory for storing images.
121+
122+
Args:
123+
year (str): The year for the content
124+
index (str): The ID for the content
125+
126+
Raises:
127+
FileExistsError: If the content path already exists
128+
"""
59129
content_path = _TARGET_BASE_PATH.joinpath(year).joinpath(index)
60130
image_path = content_path.joinpath('img')
61131

@@ -64,10 +134,18 @@ def create_base_paths(year: str, index: str):
64134

65135
os.mkdir(content_path)
66136
os.mkdir(image_path)
137+
print(f'Using year: {year} and id: {index}')
67138
print(f'Created {content_path}')
68139

69140

70141
def print_content(year: str, content_id: str):
142+
"""
143+
Print the contents of an index.md file for a specific content page.
144+
145+
Args:
146+
year (str): The year of the content
147+
content_id (str): The ID of the content
148+
"""
71149
content_path = _TARGET_BASE_PATH.joinpath(year).joinpath(content_id)
72150
index_file = content_path.joinpath('index.md')
73151
with open(index_file, 'r') as file:
@@ -76,6 +154,15 @@ def print_content(year: str, content_id: str):
76154

77155

78156
def remove_content(year: str, content_id: str):
157+
"""
158+
Remove a content page and its associated thumbnail.
159+
160+
Deletes both the content directory and the thumbnail image.
161+
162+
Args:
163+
year (str): The year of the content to remove
164+
content_id (str): The ID of the content to remove
165+
"""
79166
content_path = _TARGET_BASE_PATH.joinpath(year).joinpath(content_id)
80167
thumbnail_path = _THUMBNAIL_FULL_BASE_PATH.joinpath(year).joinpath(f'{content_id}.jpg')
81168
shutil.rmtree(content_path)
@@ -85,25 +172,71 @@ def remove_content(year: str, content_id: str):
85172

86173

87174
def parse_date_from_path(path: Path) -> datetime:
175+
"""
176+
Extract and parse a date from a directory path name.
177+
178+
Expects the directory name to start with a date in the format defined by _DATE_INPUT_FORMAT.
179+
180+
Args:
181+
path (Path): The path object containing the date in its name
182+
183+
Returns:
184+
datetime: The parsed datetime object
185+
"""
88186
date_time: str = path.name.split(' ')[0]
89187
date_time: datetime = datetime.strptime(date_time, _DATE_INPUT_FORMAT)
90188
print(f'Parsing date "{date_time}" from "{path.name}"')
91189
return date_time
92190

93191

94192
def parse_tag_from_path(path: Path) -> str:
193+
"""
194+
Extract a tag from a directory path name.
195+
196+
Expects the directory name to have a tag as the second element when split by spaces.
197+
198+
Args:
199+
path (Path): The path object containing the tag in its name
200+
201+
Returns:
202+
str: The extracted tag
203+
"""
95204
tag = path.name.split(' ')[1]
96205
print(f'Parsing tag "{tag}" from "{path.name}"')
97206
return tag
98207

99208

100209
def copy_images(year: str, content_id: str, input_path: Path):
210+
"""
211+
Copy JPEG images from an input directory to the content directory.
212+
213+
The first image found is also copied as a thumbnail.
214+
All images are renamed according to the pattern: year-contentId-counter.jpg
215+
Searches recursively through all subdirectories.
216+
217+
Args:
218+
year (str): The year for the content
219+
content_id (str): The ID for the content
220+
input_path (Path): The path to the directory containing source images
221+
222+
Raises:
223+
FileNotFoundError: If no JPEG images are found in the input directory
224+
"""
101225
content_path = _TARGET_BASE_PATH.joinpath(year).joinpath(content_id)
102226
image_path = content_path.joinpath('img')
103227
counter = 1
104228

105-
# Iterate through all files in the directory
106-
for file_path in sorted(input_path.iterdir()):
229+
# Get all files recursively
230+
all_files = []
231+
for root, _, files in os.walk(input_path):
232+
for file in files:
233+
all_files.append(Path(root) / file)
234+
235+
# Sort files to ensure consistent ordering
236+
all_files.sort()
237+
238+
# Process all image files
239+
for file_path in all_files:
107240
if file_path.is_file():
108241
mime_type, _ = mimetypes.guess_type(file_path)
109242
if mime_type and mime_type == 'image/jpeg':
@@ -116,11 +249,24 @@ def copy_images(year: str, content_id: str, input_path: Path):
116249
shutil.copy(file_path, new_image)
117250
print(f'Copy {file_path.name} to {new_image}')
118251
counter = counter + 1
252+
119253
if counter == 1:
120254
raise FileNotFoundError(f'No JPG images found in {input_path}')
121255

122256

123257
def get_images_snippet(year: str, content_id: str) -> (str, str):
258+
"""
259+
Generate resources and shortcodes snippets for all images in the content directory.
260+
261+
Creates Hugo resource declarations and image shortcodes for each image file.
262+
263+
Args:
264+
year (str): The year of the content
265+
content_id (str): The ID of the content
266+
267+
Returns:
268+
tuple: A tuple containing (resources_string, shortcodes_string)
269+
"""
124270
content_path = _TARGET_BASE_PATH.joinpath(year).joinpath(content_id)
125271
image_path = content_path.joinpath('img')
126272
index_file = content_path.joinpath('index.md')
@@ -135,10 +281,21 @@ def get_images_snippet(year: str, content_id: str) -> (str, str):
135281

136282

137283
def find_markdown_content(input_path: Path) -> str:
138-
"""Find and read the content of a markdown file in the given directory."""
284+
"""
285+
Find and read the content of a markdown file in the given directory.
286+
287+
Searches for any .md file in the input directory and returns its contents.
288+
If multiple markdown files exist, only the first one found will be used.
289+
290+
Args:
291+
input_path (Path): The directory to search for markdown files
292+
293+
Returns:
294+
str: The content of the markdown file, or an empty string if none found
295+
"""
139296
for file_path in input_path.iterdir():
140297
if file_path.is_file() and file_path.suffix == '.md':
141-
print(f'Use markdown file: {file_path.name}')
298+
print(f'Use markdown file: {file_path}')
142299
with open(file_path, 'r') as md_file:
143300
content = md_file.read()
144301
return content
@@ -155,6 +312,21 @@ def create_index_file(year: str,
155312
resources: str,
156313
shortcodes: str,
157314
markdown_content: str = ''):
315+
"""
316+
Create an index.md file for a content page using the template.
317+
318+
Formats the provided parameters into the index template and writes it to disk.
319+
320+
Args:
321+
year (str): The year of the content
322+
content_id (str): The ID of the content
323+
date (datetime): The date for the content
324+
thumbnail (str): Path to the thumbnail image
325+
tag (str): The tag for the content
326+
resources (str): The resources section for Hugo
327+
shortcodes (str): The image shortcodes
328+
markdown_content (str, optional): Additional markdown content. Defaults to ''.
329+
"""
158330
content_path = _TARGET_BASE_PATH.joinpath(year).joinpath(content_id)
159331
index_file = content_path.joinpath('index.md')
160332

2.78 MB
Loading
3.08 MB
Loading
1.83 MB
Loading
968 KB
Loading
2.19 MB
Loading
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
title: Feuer 3. Alarm brennt Dach - Einsatz Cobra-System
3+
date: 2025-03-06 15:17:00
4+
description: Feuer 3. Alarm brennt Dach - Einsatz Cobra-System
5+
thumbnail: img/einsaetze/2025/0003.jpg
6+
tag: FEU3NOTF
7+
resources:
8+
- name: img01
9+
src: img/2025-0003-01.jpg
10+
- name: img02
11+
src: img/2025-0003-02.jpg
12+
- name: img03
13+
src: img/2025-0003-03.jpg
14+
- name: img04
15+
src: img/2025-0003-04.jpg
16+
- name: img05
17+
src: img/2025-0003-05.jpg
18+
---
19+
20+
Feuer 3. Alarm brennt Dach - Einsatz Cobra-System
21+
22+
Am Donnerstagnachmittag, den 06.03.2025 gegen 15:30 Uhr wurde die FF Eppendorf zusammen mit weiteren Einsatzkräften aufgrund des Alarmierungstichwortes FEU2 brennt Dach mit dem Einsatzmodul Cobra zu einem ausgedehnten Dachstuhlbrand in den Stadtteil Rotherbaum alarmiert.
23+
Aufgrund des Flammenschlages und der starken Rauchentwicklung wurde zügig von den Einsatzkräften auf 3. Alarm erhöht.
24+
Nach Dacharbeiten standen Teile des Dachgeschosses, sowie des Daches eines fünfgeschossigen Wohngebäudes im Vollbrand.
25+
Das Feuer hatte sich bis in die Dachzwischenräume ausgebreitet.
26+
27+
Unser primärer Einsatzauftrag, zusammen mit den Kräften der Technik- und Umweltschutzwache F32, bestand darin, die unzugänglichen Bereiche des Dachgeschosses zu erkunden und mittels des Cobra Cold Cut Lösch- und Schneidsystems gezielt zu löschen.
28+
Das Cobra-Cold-Cut-System wurde dabei über die DLK 11 nach oben verbracht.
29+
Unsere speziell ausgebildeten Atemschutztrupps gingen hierbei zusammen mit unserem Einheitsführer Cobra über das Baugerüst bis ins eingerüstete Dachgeschoss vor.
30+
Durch den taktische Einsatz in Verbindung mit der Wärmebildkamera konnten mehere HotSpots kurzfristig identifiziert und abgelöscht werden.
31+
Das Cobra-System bietet die Möglichkeit mittels 300bar Wasserdruck mit beigemischtem Abrasivstoff z.B. durch Wände oder die Dachhaut zu schießen und dahinterliegende Räume zu kühlen bzw.
32+
Glutnester in Zwischenräumen zu löschen. Ein geringer Wasserdurchsatz lässt dadurch Schäden minimieren.
33+
34+
Der Technische Zug war mit 2 Fahrzeugen und 15 Einsatzkräften darunter 11 AGT mehrere Stunden im Einsatz.
35+
Eine umfangreiche Einsatzhygiene konnte bereits vor Ort durchgeführt werden.
36+
37+
38+
[Offizieller Pressebericht](https://www.presseportal.de/blaulicht/pm/82522/5985473)
39+
40+
Bilder mit freundlicher Genehmigung: Michael Arning
41+
42+
{{< image src="img01" >}}
43+
{{< image src="img02" >}}
44+
{{< image src="img03" >}}
45+
{{< image src="img04" >}}
46+
{{< image src="img05" >}}
2.57 MB
Loading

0 commit comments

Comments
 (0)