djhx-blogger 0.1.6__py3-none-any.whl → 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of djhx-blogger might be problematic. Click here for more details.
- djhx_blogger/gen.py +138 -3
- djhx_blogger/static/images/mountain.jpg +0 -0
- djhx_blogger-0.1.9.dist-info/METADATA +42 -0
- {djhx_blogger-0.1.6.dist-info → djhx_blogger-0.1.9.dist-info}/RECORD +8 -7
- djhx_blogger-0.1.6.dist-info/METADATA +0 -12
- {djhx_blogger-0.1.6.dist-info → djhx_blogger-0.1.9.dist-info}/WHEEL +0 -0
- {djhx_blogger-0.1.6.dist-info → djhx_blogger-0.1.9.dist-info}/entry_points.txt +0 -0
- {djhx_blogger-0.1.6.dist-info → djhx_blogger-0.1.9.dist-info}/licenses/LICENSE +0 -0
- {djhx_blogger-0.1.6.dist-info → djhx_blogger-0.1.9.dist-info}/top_level.txt +0 -0
djhx_blogger/gen.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import shutil
|
|
2
3
|
import time
|
|
3
|
-
from collections import deque, OrderedDict
|
|
4
|
+
from collections import deque, OrderedDict, defaultdict
|
|
4
5
|
from importlib import resources
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import markdown
|
|
9
|
+
from PIL import Image
|
|
8
10
|
from bs4 import BeautifulSoup
|
|
9
11
|
from jinja2 import Template
|
|
10
12
|
|
|
@@ -19,6 +21,10 @@ def load_template(name: str) -> str:
|
|
|
19
21
|
file_path = resources.files("djhx_blogger.static.template").joinpath(name)
|
|
20
22
|
return file_path.read_text(encoding="utf-8")
|
|
21
23
|
|
|
24
|
+
def load_image(img_name: str) -> Path:
|
|
25
|
+
file_path = resources.files("djhx_blogger.static.images").joinpath(img_name)
|
|
26
|
+
return Path(str(file_path))
|
|
27
|
+
|
|
22
28
|
|
|
23
29
|
class Node:
|
|
24
30
|
cache_map = {}
|
|
@@ -254,7 +260,12 @@ def gen_blog_dir(root: Node):
|
|
|
254
260
|
with open(node.destination_path, mode='w', encoding='utf-8') as f:
|
|
255
261
|
f.write(gen_article_index(node.source_path, node.source_path.parent.name))
|
|
256
262
|
else:
|
|
257
|
-
shutil.copy(node.source_path, node.destination_path)
|
|
263
|
+
# shutil.copy(node.source_path, node.destination_path)
|
|
264
|
+
# 图片压缩
|
|
265
|
+
start_time = int(time.time() * 1000)
|
|
266
|
+
compress_image(node.source_path, node.destination_path)
|
|
267
|
+
end_time = int(time.time() * 1000)
|
|
268
|
+
logger.info(f'压缩图片耗时: {(end_time-start_time)} ms | {node.source_path} -> {node.destination_path}')
|
|
258
269
|
|
|
259
270
|
end = int(time.time() * 1000)
|
|
260
271
|
logger.info(f'生成目标目录耗时: {end - start} ms')
|
|
@@ -352,6 +363,118 @@ def parse_metadata(metadata):
|
|
|
352
363
|
return meta_dict
|
|
353
364
|
|
|
354
365
|
|
|
366
|
+
|
|
367
|
+
def compress_image(input_path, output_path, quality=70, max_size=(960, 540)):
|
|
368
|
+
"""
|
|
369
|
+
压缩图片到指定质量和最大尺寸。
|
|
370
|
+
- input_path: 源图片路径
|
|
371
|
+
- output_path: 输出路径,默认覆盖源文件
|
|
372
|
+
- quality: 压缩质量(0~100)
|
|
373
|
+
- max_size: 限制最大宽高(超过则等比缩小)
|
|
374
|
+
"""
|
|
375
|
+
if not input_path or not output_path:
|
|
376
|
+
logger.warning(f'图片压缩 input/output path 不能为空')
|
|
377
|
+
return
|
|
378
|
+
|
|
379
|
+
with Image.open(input_path).convert("RGB") as img:
|
|
380
|
+
img.thumbnail(max_size)
|
|
381
|
+
img.save(output_path, optimize=True, quality=quality)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def analyze_directory_size(directory_path):
|
|
385
|
+
"""
|
|
386
|
+
分析目录下不同类型文件的数量和占用空间
|
|
387
|
+
|
|
388
|
+
参数:
|
|
389
|
+
directory_path: 要分析的目录路径
|
|
390
|
+
|
|
391
|
+
返回:
|
|
392
|
+
dict: 包含文件类型统计信息的字典
|
|
393
|
+
"""
|
|
394
|
+
# 存储统计结果的字典
|
|
395
|
+
file_stats = defaultdict(lambda: {'count': 0, 'size_bytes': 0})
|
|
396
|
+
|
|
397
|
+
# 遍历目录及其所有子目录
|
|
398
|
+
for root, dirs, files in os.walk(directory_path):
|
|
399
|
+
for file in files:
|
|
400
|
+
file_path = os.path.join(root, file)
|
|
401
|
+
|
|
402
|
+
try:
|
|
403
|
+
# 获取文件大小
|
|
404
|
+
file_size = os.path.getsize(file_path)
|
|
405
|
+
|
|
406
|
+
# 获取文件扩展名(转换为小写,去掉点)
|
|
407
|
+
file_ext = Path(file).suffix.lower()
|
|
408
|
+
if not file_ext:
|
|
409
|
+
file_ext = '无扩展名'
|
|
410
|
+
else:
|
|
411
|
+
file_ext = file_ext[1:] # 去掉前面的点
|
|
412
|
+
|
|
413
|
+
# 更新统计信息
|
|
414
|
+
file_stats[file_ext]['count'] += 1
|
|
415
|
+
file_stats[file_ext]['size_bytes'] += file_size
|
|
416
|
+
|
|
417
|
+
except (OSError, IOError):
|
|
418
|
+
# 跳过无法访问的文件
|
|
419
|
+
continue
|
|
420
|
+
|
|
421
|
+
return file_stats
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def format_size(size_bytes):
|
|
425
|
+
"""
|
|
426
|
+
将字节数转换为易读的格式
|
|
427
|
+
|
|
428
|
+
参数:
|
|
429
|
+
size_bytes: 字节数
|
|
430
|
+
|
|
431
|
+
返回:
|
|
432
|
+
str: 格式化后的大小字符串
|
|
433
|
+
"""
|
|
434
|
+
if size_bytes == 0:
|
|
435
|
+
return "0B"
|
|
436
|
+
|
|
437
|
+
size_names = ["B", "KB", "MB", "GB", "TB"]
|
|
438
|
+
i = 0
|
|
439
|
+
while size_bytes >= 1024 and i < len(size_names) - 1:
|
|
440
|
+
size_bytes /= 1024.0
|
|
441
|
+
i += 1
|
|
442
|
+
|
|
443
|
+
# 根据大小选择合适的精度
|
|
444
|
+
if i == 0: # B
|
|
445
|
+
return f"{int(size_bytes)}{size_names[i]}"
|
|
446
|
+
elif i <= 2: # KB, MB
|
|
447
|
+
return f"{size_bytes:.1f}{size_names[i]}"
|
|
448
|
+
else: # GB, TB
|
|
449
|
+
return f"{size_bytes:.2f}{size_names[i]}"
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def print_directory_stats(directory_path):
|
|
453
|
+
"""
|
|
454
|
+
打印目录统计信息
|
|
455
|
+
|
|
456
|
+
参数:
|
|
457
|
+
directory_path: 要分析的目录路径
|
|
458
|
+
"""
|
|
459
|
+
stats = analyze_directory_size(directory_path)
|
|
460
|
+
|
|
461
|
+
if not stats:
|
|
462
|
+
print("目录为空或无法访问")
|
|
463
|
+
return
|
|
464
|
+
|
|
465
|
+
# 按文件大小排序
|
|
466
|
+
sorted_stats = sorted(stats.items(), key=lambda x: x[1]['size_bytes'], reverse=True)
|
|
467
|
+
|
|
468
|
+
# 打印表头
|
|
469
|
+
print(f"{'类型':<10} | {'数量':<6} | {'大小':<10}")
|
|
470
|
+
print("-" * 30)
|
|
471
|
+
|
|
472
|
+
# 打印每种文件类型的统计信息
|
|
473
|
+
for file_type, data in sorted_stats:
|
|
474
|
+
count = data['count']
|
|
475
|
+
size_str = format_size(data['size_bytes'])
|
|
476
|
+
print(f"{file_type:<10} | {count:<6} | {size_str:<10}")
|
|
477
|
+
|
|
355
478
|
def generate_blog(blog_dir: str, blog_target: str):
|
|
356
479
|
start = time.time()
|
|
357
480
|
|
|
@@ -362,13 +485,17 @@ def generate_blog(blog_dir: str, blog_target: str):
|
|
|
362
485
|
cp_resource(blog_target)
|
|
363
486
|
|
|
364
487
|
end = time.time()
|
|
365
|
-
logger.info(f'生成静态博客 {blog_dir}, 任务完成, 总耗时: {int((end-start)*1000)} ms')
|
|
488
|
+
logger.info(f'生成静态博客 {blog_dir} -> {root_node.destination_path}, 任务完成, 总耗时: {int((end-start)*1000)} ms')
|
|
489
|
+
print_directory_stats(root_node.destination_path)
|
|
490
|
+
|
|
366
491
|
return root_node
|
|
367
492
|
|
|
368
493
|
|
|
369
494
|
def init_new_blog(blog_dir: str):
|
|
370
495
|
blog_dir_path = Path(blog_dir) / "simple-blog" / "demo-article"
|
|
496
|
+
blog_images_dir_path = blog_dir_path / "images"
|
|
371
497
|
blog_dir_path.mkdir(parents=True, exist_ok=True)
|
|
498
|
+
blog_images_dir_path.mkdir(parents=True, exist_ok=True)
|
|
372
499
|
with open(blog_dir_path / 'index.md', 'w', encoding='utf-8') as file:
|
|
373
500
|
file.write(f"""---
|
|
374
501
|
title: "Demo Post"
|
|
@@ -380,9 +507,17 @@ summary: "simple demo article"
|
|
|
380
507
|
|
|
381
508
|
## title 1
|
|
382
509
|
|
|
510
|
+
mountain images:
|
|
511
|
+
|
|
512
|
+

|
|
513
|
+
|
|
383
514
|
### title 2
|
|
384
515
|
|
|
385
516
|
This is a simple demo...
|
|
386
517
|
"""
|
|
387
518
|
)
|
|
388
519
|
file.write('')
|
|
520
|
+
|
|
521
|
+
mountain_img = load_image('mountain.jpg')
|
|
522
|
+
logger.info(mountain_img)
|
|
523
|
+
shutil.copy2(mountain_img, blog_images_dir_path / 'mountain.jpg')
|
|
Binary file
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: djhx-blogger
|
|
3
|
+
Version: 0.1.9
|
|
4
|
+
Summary: A simple static site generator, support only markdown file.
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: beautifulsoup4>=4.14.2
|
|
9
|
+
Requires-Dist: fabric>=3.2.2
|
|
10
|
+
Requires-Dist: jinja2>=3.1.6
|
|
11
|
+
Requires-Dist: markdown>=3.9
|
|
12
|
+
Requires-Dist: pillow>=11.3.0
|
|
13
|
+
Requires-Dist: typer>=0.20.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# djhx-blogger
|
|
17
|
+
|
|
18
|
+
一个个人使用的博客生成器。
|
|
19
|
+
|
|
20
|
+
## 命令
|
|
21
|
+
|
|
22
|
+
查看帮助
|
|
23
|
+
```shell
|
|
24
|
+
blg --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
生成一个示例博客目录
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
blg -n "C:\Users\ABC\Desktop\"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
生成静态页面
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
blg -o "C:\Users\ABC\Desktop\simple-blog\"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## TODO
|
|
40
|
+
|
|
41
|
+
1. 图片压缩
|
|
42
|
+
2. 博客网站 title 和 nav-bar 的模板化
|
|
@@ -2,19 +2,20 @@ djhx_blogger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
2
2
|
djhx_blogger/__main__.py,sha256=MwMXMO3kuvG-luTG4lnLwjEnqnm20lI-amV9sETColo,61
|
|
3
3
|
djhx_blogger/cli.py,sha256=IT_hPolwqGsPbOLWwbQymfsHZtUyatgskXYue70UoFE,2013
|
|
4
4
|
djhx_blogger/deploy.py,sha256=tHJrOHaW8vQqN-YfpRLpjZOaUDXrWk_NVXnvPM014Hc,2056
|
|
5
|
-
djhx_blogger/gen.py,sha256=
|
|
5
|
+
djhx_blogger/gen.py,sha256=nfDws6xSHAnMP2SBGq6VkT-hWkD3wIclINJ-mx8FcJw,17291
|
|
6
6
|
djhx_blogger/log_config.py,sha256=aEvShHNahBO52w5I6WU4U2yTMAO7qIezcH2K1vSnbVo,871
|
|
7
7
|
djhx_blogger/static/css/archive.css,sha256=Jkfl7HlQ-zsRDT4nFaR0WR7m3-AwCXsWVlLWBLdWVNM,855
|
|
8
8
|
djhx_blogger/static/css/article.css,sha256=lCuMUOia2E7_E_OG7c2Gc7JMr-RdoyASQQ2mB6J2qKo,3239
|
|
9
9
|
djhx_blogger/static/css/basic.css,sha256=gSKoyM_3GwoNGg3wScrVNl9ccnZwkw_ffnxODu_wbko,1152
|
|
10
10
|
djhx_blogger/static/css/category.css,sha256=DBjUWZiaZO8uzpl2iY3acEVYzigW2HM3dHRfh2zNjok,2351
|
|
11
11
|
djhx_blogger/static/images/favicon.ico,sha256=N0NH9yMTUzEZhGomQKeYohKP1MmL5CfmtsZi3jdlbvU,45497
|
|
12
|
+
djhx_blogger/static/images/mountain.jpg,sha256=lY64nDTxXm86MEKMhSZ0FaZSmKQ72tlIb-8cRl6AeC8,766801
|
|
12
13
|
djhx_blogger/static/template/archive.html,sha256=aTeyirij9reMl1WmDTmZVHF0yip3c8RoAam4tj6RIo8,1340
|
|
13
14
|
djhx_blogger/static/template/article.html,sha256=GgU1mZrfAd-T3Y4Z0bqOljdkGI89p-OsuCAU4IHrTwE,1246
|
|
14
15
|
djhx_blogger/static/template/category.html,sha256=KRjTJw-8G3bs_LrhfeEm7xYtBON5v0pLKTPwf_PD_Uo,1607
|
|
15
|
-
djhx_blogger-0.1.
|
|
16
|
-
djhx_blogger-0.1.
|
|
17
|
-
djhx_blogger-0.1.
|
|
18
|
-
djhx_blogger-0.1.
|
|
19
|
-
djhx_blogger-0.1.
|
|
20
|
-
djhx_blogger-0.1.
|
|
16
|
+
djhx_blogger-0.1.9.dist-info/licenses/LICENSE,sha256=Whbb1w0-YAwWeAth-B6_jXSPWx9Fum73B0R-Z_lzUjA,1085
|
|
17
|
+
djhx_blogger-0.1.9.dist-info/METADATA,sha256=Jufi_kHTmoD5Yq1iJmKC3ihHLn3sBdFHix40DXoSapU,791
|
|
18
|
+
djhx_blogger-0.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
+
djhx_blogger-0.1.9.dist-info/entry_points.txt,sha256=3rA_ZPnqdFHrqaZ0ATmrrScDNSN-Jcs7efeyC4q2Do0,45
|
|
20
|
+
djhx_blogger-0.1.9.dist-info/top_level.txt,sha256=FZNu1SEldZAx_j_NmZoOxLha4G8-0KndmlFiPjPfJIk,13
|
|
21
|
+
djhx_blogger-0.1.9.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: djhx-blogger
|
|
3
|
-
Version: 0.1.6
|
|
4
|
-
Summary: A simple static site generator, support only markdown file.
|
|
5
|
-
Requires-Python: >=3.9
|
|
6
|
-
License-File: LICENSE
|
|
7
|
-
Requires-Dist: beautifulsoup4>=4.14.2
|
|
8
|
-
Requires-Dist: fabric>=3.2.2
|
|
9
|
-
Requires-Dist: jinja2>=3.1.6
|
|
10
|
-
Requires-Dist: markdown>=3.9
|
|
11
|
-
Requires-Dist: typer>=0.20.0
|
|
12
|
-
Dynamic: license-file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|