plugin-jm-server 0.1.23__tar.gz → 0.2.0__tar.gz

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.
Files changed (60) hide show
  1. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/PKG-INFO +45 -4
  2. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/README.md +33 -2
  3. plugin_jm_server-0.2.0/src/plugin_jm_server/__init__.py +3 -0
  4. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/app.py +95 -7
  5. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/driver.py +6 -5
  6. plugin_jm_server-0.2.0/src/plugin_jm_server/files.py +170 -0
  7. plugin_jm_server-0.2.0/src/plugin_jm_server/static/css/index.css +729 -0
  8. plugin_jm_server-0.2.0/src/plugin_jm_server/static/css/index_spa.css +556 -0
  9. plugin_jm_server-0.2.0/src/plugin_jm_server/static/css/style_photo.css +1 -0
  10. plugin_jm_server-0.2.0/src/plugin_jm_server/static/img/bg.jpg +0 -0
  11. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/common.js +78 -0
  12. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/index.js +317 -0
  13. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/index_spa.js +612 -0
  14. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/jquery.lazyload-2.0.js +444 -0
  15. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/jquery.photo-0.3.js +427 -0
  16. plugin_jm_server-0.2.0/src/plugin_jm_server/templates/index.html +191 -0
  17. plugin_jm_server-0.2.0/src/plugin_jm_server/templates/index_spa.html +118 -0
  18. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/jm_view.html +10 -3
  19. plugin_jm_server-0.2.0/src/plugin_jm_server/templates/m_index.html +187 -0
  20. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/PKG-INFO +45 -4
  21. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/SOURCES.txt +5 -0
  22. plugin_jm_server-0.1.23/src/plugin_jm_server/__init__.py +0 -3
  23. plugin_jm_server-0.1.23/src/plugin_jm_server/files.py +0 -119
  24. plugin_jm_server-0.1.23/src/plugin_jm_server/static/css/index.css +0 -200
  25. plugin_jm_server-0.1.23/src/plugin_jm_server/static/css/style_photo.css +0 -1
  26. plugin_jm_server-0.1.23/src/plugin_jm_server/static/img/bg.jpg +0 -0
  27. plugin_jm_server-0.1.23/src/plugin_jm_server/static/js/common.js +0 -49
  28. plugin_jm_server-0.1.23/src/plugin_jm_server/static/js/index.js +0 -95
  29. plugin_jm_server-0.1.23/src/plugin_jm_server/templates/index.html +0 -100
  30. plugin_jm_server-0.1.23/src/plugin_jm_server/templates/m_index.html +0 -92
  31. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/setup.cfg +0 -0
  32. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/setup.py +0 -0
  33. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/all.min.css +0 -0
  34. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/bootstrap.css +0 -0
  35. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/download_error.css +0 -0
  36. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_download_error.css +0 -0
  37. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_index.css +0 -0
  38. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_login.css +0 -0
  39. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_upload.css +0 -0
  40. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/normalize.css +0 -0
  41. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/login.css +0 -0
  42. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/upload.css +0 -0
  43. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/img/m_bg.jpeg +0 -0
  44. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/h5/m_index.js +0 -0
  45. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/h5/m_upload.js +0 -0
  46. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/jquery-3.7.1.min.js +0 -0
  47. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/jquery.album-0.2.js +0 -0
  48. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/upload.js +0 -0
  49. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/webfonts/fa-regular-400.woff2 +0 -0
  50. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/webfonts/fa-solid-900.woff2 +0 -0
  51. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/download_error.html +0 -0
  52. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/login.html +0 -0
  53. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_download_error.html +0 -0
  54. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_jm_view.html +0 -0
  55. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_login.html +0 -0
  56. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_upload.html +0 -0
  57. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/upload.html +0 -0
  58. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/dependency_links.txt +0 -0
  59. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/requires.txt +0 -0
  60. {plugin_jm_server-0.1.23 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: plugin_jm_server
3
- Version: 0.1.23
3
+ Version: 0.2.0
4
4
  Summary: plugin_jm_server, a plugin for jmcomic that can be used to view comics in a web browser.
5
5
  Home-page: https://github.com/hect0x7/plugin-jm-server
6
6
  Author: hect0x7
@@ -23,9 +23,29 @@ Requires-Dist: jmcomic
23
23
  Requires-Dist: flask
24
24
  Requires-Dist: psutil
25
25
  Requires-Dist: cryptography
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: requires-dist
34
+ Dynamic: requires-python
35
+ Dynamic: summary
26
36
 
27
37
  # plugin-jm-server
28
38
 
39
+ “离线版”禁漫天堂
40
+
41
+ 该项目会在本地起一个`文件服务器`,支持用浏览器查看文件夹内的图片,界面模仿禁漫的章节观看页面,并适配手机端。
42
+
43
+ 用浏览器的好处就是支持很多浏览器插件和脚本,例如:
44
+
45
+ * 双页阅读插件:https://sleazyfork.org/zh-CN/scripts/374903-comicread
46
+
47
+ # 想法起源
48
+
29
49
  想法起源:https://github.com/hect0x7/JMComic-Crawler-Python/issues/192
30
50
 
31
51
  基于原项目:https://github.com/AiCorein/Flask-Files-Server
@@ -33,9 +53,14 @@ Requires-Dist: cryptography
33
53
  为了方便修改,将原项目中的文件复制到本项目中,然后进行修改
34
54
 
35
55
 
56
+ # 可优化点
57
+
58
+ 1. 前端优化。目前项目架构是`前后端不分离架构`,前端使用原始的html三件套。可以优化为前后端分离架构,基于Vue等开发框架,复用组件库,优化界面。
59
+
60
+ 2. 后端优化。支持提供调用jmcomic功能的后端接口。
36
61
 
37
- # 使用方式
38
62
 
63
+ # 使用方式
39
64
 
40
65
 
41
66
  ## 1. pip安装
@@ -113,12 +138,28 @@ op.wait_all_plugins_finish()
113
138
  # 效果图(文件浏览、整章看图)
114
139
 
115
140
  ## 1. 电脑浏览器访问
141
+
142
+ ### 登录页
116
143
  ![](images/3.png)
144
+
145
+ ### 文件夹列表页
117
146
  ![](images/4.png)
147
+ ![](images/9.png)
148
+
149
+ ### 看本模式
118
150
  ![](images/5.png)
119
151
 
152
+ ### 文件夹&看本 二合一模式
153
+ ![](images/8.png)
154
+
120
155
  ## 2. 手机浏览器访问
156
+
157
+ ### 登录页
121
158
  ![](images/1.jpeg)
122
- ![](images/2.jpeg)
159
+
160
+ ### 文件夹列表页
161
+ ![](images/2.png)
162
+
163
+ ### 看本模式
123
164
  ![](images/7.jpeg)
124
165
 
@@ -1,5 +1,15 @@
1
1
  # plugin-jm-server
2
2
 
3
+ “离线版”禁漫天堂
4
+
5
+ 该项目会在本地起一个`文件服务器`,支持用浏览器查看文件夹内的图片,界面模仿禁漫的章节观看页面,并适配手机端。
6
+
7
+ 用浏览器的好处就是支持很多浏览器插件和脚本,例如:
8
+
9
+ * 双页阅读插件:https://sleazyfork.org/zh-CN/scripts/374903-comicread
10
+
11
+ # 想法起源
12
+
3
13
  想法起源:https://github.com/hect0x7/JMComic-Crawler-Python/issues/192
4
14
 
5
15
  基于原项目:https://github.com/AiCorein/Flask-Files-Server
@@ -7,9 +17,14 @@
7
17
  为了方便修改,将原项目中的文件复制到本项目中,然后进行修改
8
18
 
9
19
 
20
+ # 可优化点
21
+
22
+ 1. 前端优化。目前项目架构是`前后端不分离架构`,前端使用原始的html三件套。可以优化为前后端分离架构,基于Vue等开发框架,复用组件库,优化界面。
23
+
24
+ 2. 后端优化。支持提供调用jmcomic功能的后端接口。
10
25
 
11
- # 使用方式
12
26
 
27
+ # 使用方式
13
28
 
14
29
 
15
30
  ## 1. pip安装
@@ -87,12 +102,28 @@ op.wait_all_plugins_finish()
87
102
  # 效果图(文件浏览、整章看图)
88
103
 
89
104
  ## 1. 电脑浏览器访问
105
+
106
+ ### 登录页
90
107
  ![](images/3.png)
108
+
109
+ ### 文件夹列表页
91
110
  ![](images/4.png)
111
+ ![](images/9.png)
112
+
113
+ ### 看本模式
92
114
  ![](images/5.png)
93
115
 
116
+ ### 文件夹&看本 二合一模式
117
+ ![](images/8.png)
118
+
94
119
  ## 2. 手机浏览器访问
120
+
121
+ ### 登录页
95
122
  ![](images/1.jpeg)
96
- ![](images/2.jpeg)
123
+
124
+ ### 文件夹列表页
125
+ ![](images/2.png)
126
+
127
+ ### 看本模式
97
128
  ![](images/7.jpeg)
98
129
 
@@ -0,0 +1,3 @@
1
+ __version__ = '0.2.0'
2
+
3
+ from .app import *
@@ -8,7 +8,7 @@ from typing import Optional
8
8
  import common
9
9
  from flask import Flask, abort, Response, stream_with_context
10
10
  from flask import render_template, send_from_directory
11
- from flask import request, session, redirect, flash
11
+ from flask import request, session, redirect, flash, jsonify
12
12
 
13
13
  from .files import FileManager
14
14
 
@@ -22,10 +22,12 @@ class JmServer:
22
22
  def __init__(self,
23
23
  default_path,
24
24
  password,
25
+ *,
25
26
  jm_option=None,
26
27
  ip_whitelist=None,
27
28
  current_path=None,
28
29
  img_overwrite: Optional[dict] = None,
30
+ env=None,
29
31
  **extra,
30
32
  ):
31
33
  """
@@ -59,6 +61,9 @@ class JmServer:
59
61
  import queue
60
62
  self.jm_log_msg_queue = queue.Queue()
61
63
  self.__hook_jm_logging()
64
+ if env:
65
+ for k, v in env.items():
66
+ os.environ[k] = v
62
67
 
63
68
  def __hook_jm_logging(self):
64
69
  import jmcomic
@@ -77,7 +82,7 @@ class JmServer:
77
82
  """
78
83
  验证登录状态
79
84
  """
80
- if session.get('password', None) == self.password:
85
+ if (self.password == '') or session.get('password', None) == self.password:
81
86
  return True
82
87
  else:
83
88
  return False
@@ -112,9 +117,75 @@ class JmServer:
112
117
  """
113
118
  url添加一个随机参数,防止浏览器缓存
114
119
  """
115
- # from random import randint
116
- # return randint(100000, 1000000)
117
- return 0
120
+ from random import randint
121
+ return randint(100000, 1000000)
122
+
123
+ def spa_view(self):
124
+ """
125
+ [New] V2 SPA Interface (PC Only)
126
+ """
127
+ if not self.verify():
128
+ return redirect('/login')
129
+
130
+ # 获取路径参数,如果为空则使用默认路径
131
+ path = request.args.get('path', None)
132
+ if path is None:
133
+ path = self.file_manager.default_path
134
+
135
+ path = os.path.abspath(path)
136
+ path = common.fix_filepath(path)
137
+
138
+ if common.file_not_exists(path):
139
+ return abort(404)
140
+
141
+ return render_template('index_spa.html',
142
+ data={
143
+ 'currentPath': path,
144
+ 'defaultPath': self.file_manager.default_path,
145
+ 'drivers': self.file_manager.DRIVERS_LIST
146
+ },
147
+ randomArg=self.url_random_arg())
148
+
149
+ def api_list_files(self):
150
+ """
151
+ [New] API: List files in directory
152
+ """
153
+ if not self.verify():
154
+ return abort(403)
155
+
156
+ path = request.args.get('path', self.file_manager.default_path)
157
+ path = os.path.abspath(path)
158
+ path = common.fix_filepath(path)
159
+
160
+ if common.file_not_exists(path):
161
+ return jsonify({'error': 'Path not found'}), 404
162
+
163
+ files_data = self.file_manager.get_files_data(path)
164
+ return jsonify({
165
+ 'currentPath': path,
166
+ 'files': files_data
167
+ })
168
+
169
+ def api_album_images(self):
170
+ """
171
+ [New] API: Get images for an album
172
+ """
173
+ if not self.verify():
174
+ return abort(403)
175
+
176
+ path = request.args.get('path', None)
177
+ if not path:
178
+ return jsonify({'error': 'Path required'}), 400
179
+
180
+ path = os.path.abspath(path)
181
+ if common.file_not_exists(path):
182
+ return jsonify({'error': 'Path not found'}), 404
183
+
184
+ images = self.file_manager.get_jm_view_images(path)
185
+ return jsonify({
186
+ 'title': common.of_file_name(path),
187
+ 'images': images
188
+ })
118
189
 
119
190
  def jm_view(self):
120
191
  """
@@ -189,6 +260,7 @@ class JmServer:
189
260
  "files": self.file_manager.get_files_data(path),
190
261
  "drivers": self.file_manager.DRIVERS_LIST,
191
262
  "currentPath": path,
263
+ "defaultPath": self.file_manager.default_path
192
264
  },
193
265
  randomArg=self.url_random_arg())
194
266
 
@@ -314,8 +386,14 @@ class JmServer:
314
386
  finally:
315
387
  self.jm_log_msg_queue.put(end)
316
388
 
317
- def run(self, **kwargs):
318
- kwargs.setdefault('port', self.DEFAULT_PORT)
389
+ def open_directory(self, directory):
390
+ path = os.path.abspath(directory)
391
+ # os.startfile(path) # Windows特有,打开文件夹
392
+ import subprocess
393
+ subprocess.Popen(f'explorer /select,"{path}"')
394
+ return ''
395
+
396
+ def register_routes(self):
319
397
  # 添加路由
320
398
  self.app.add_url_rule('/jm_view', 'jm_view', self.jm_view, methods=['GET'])
321
399
  self.app.add_url_rule("/view_file/", 'view_file', self.view_file, methods=['GET'], strict_slashes=False)
@@ -323,8 +401,18 @@ class JmServer:
323
401
  self.app.add_url_rule('/login', 'login', self.login, methods=['GET', 'POST'])
324
402
  self.app.add_url_rule('/logout', 'logout', self.logout, methods=['GET', 'POST'])
325
403
  self.app.add_url_rule("/download_file/<filename>", 'file_content', self.file_content)
404
+ self.app.add_url_rule('/open/<path:directory>', 'open_directory', self.open_directory)
326
405
  self.app.add_url_rule("/upload_file", 'upload', self.upload, methods=['GET', 'POST'])
327
406
  self.app.add_url_rule("/stream", 'stream', self.stream, methods=['GET', 'POST'])
407
+
408
+ # [New] SPA Routes
409
+ self.app.add_url_rule("/spa", 'spa_view', self.spa_view, methods=['GET'])
410
+ self.app.add_url_rule("/api/list_files", 'api_list_files', self.api_list_files, methods=['GET'])
411
+ self.app.add_url_rule("/api/album_images", 'api_album_images', self.api_album_images, methods=['GET'])
412
+
413
+ def run(self, **kwargs):
414
+ kwargs.setdefault('port', self.DEFAULT_PORT)
415
+ self.register_routes()
328
416
  # 监听在所有 IP 地址上
329
417
  self.app.run(**kwargs)
330
418
 
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import re
2
3
 
3
4
 
4
5
  def get_winDriver():
@@ -23,11 +24,11 @@ def get_winDriver():
23
24
  driver_list[i] = driver_name
24
25
  i += 1
25
26
  except PermissionError as e:
26
- if '[WinError 21]' in str(e):
27
- del driver_list[i]
28
- # 异常类型不为 “设备未就绪” 的再次抛出异常供调试
29
- else:
30
- raise (PermissionError, e)
27
+ del driver_list[i]
28
+ mobj = re.match(r'\[WinError (\d+)\]', str(e))
29
+ # ERROR_NOT_READY, ERROR_ACCESS_DENIED
30
+ if mobj is not None and mobj.group(1) not in {'21', '5'}:
31
+ print(f'Drive {driver_name} unexpectedly unavailable: {e}')
31
32
  finally:
32
33
  num -= 1
33
34
 
@@ -0,0 +1,170 @@
1
+ from urllib.parse import quote
2
+ import os
3
+ import time
4
+ import re
5
+
6
+ import common
7
+
8
+
9
+ class FileManager:
10
+ def __init__(self, default_path, current_path):
11
+ self.default_path = default_path
12
+ self.current_path = current_path
13
+
14
+ @property
15
+ def DRIVERS_LIST(self):
16
+ # 判断如果是windows系统
17
+ if os.name == 'nt':
18
+ from .driver import get_winDriver
19
+ return get_winDriver()
20
+ else:
21
+ return ['/']
22
+
23
+ def get_jm_view_images(self, path):
24
+ images_data = []
25
+
26
+ give_up_sort = False
27
+
28
+ for f in self.files_of_dir_safe(path):
29
+ if not self.is_image_file(f):
30
+ continue
31
+ f = quote(f)
32
+ name = common.of_file_name(f)
33
+ try:
34
+ index = int(name[:name.index('.')])
35
+ except ValueError:
36
+ give_up_sort = True
37
+ index = None
38
+
39
+ images_data.append({
40
+ 'filename': name,
41
+ 'data_original': f'/view_file?path={f}',
42
+ 'index': index,
43
+ })
44
+
45
+ if give_up_sort is False:
46
+ images_data.sort(key=lambda item: item['index'])
47
+
48
+ return images_data
49
+
50
+ @staticmethod
51
+ def is_image_file(filename):
52
+ file_extension = filename.lower().split('.')[-1]
53
+ image_extensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'webp']
54
+ return file_extension in image_extensions
55
+
56
+ @staticmethod
57
+ def files_of_dir_safe(dir_path):
58
+ try:
59
+ return common.files_of_dir(dir_path)
60
+ except OSError:
61
+ return []
62
+
63
+ def check_dir_can_open_jm_view(self, dirpath):
64
+ return any(f for f in self.files_of_dir_safe(dirpath) if self.is_image_file(f))
65
+
66
+ def build_one_path_info(self, file_path, dtype=''):
67
+ jm_view, the_type = self.get_file_type(file_path)
68
+
69
+ name = common.of_file_name(file_path)
70
+
71
+ try:
72
+ size = os.path.getsize(file_path)
73
+ except OSError:
74
+ return
75
+
76
+ size = dtype if dtype != '' else self.file_size_format(size, the_type)
77
+
78
+ try:
79
+ getctime = os.path.getctime(file_path)
80
+ ctime = time.localtime(getctime)
81
+ time_str = time.strftime("%Y-%m-%d %H:%M:%S", ctime)
82
+ except OSError:
83
+ return
84
+
85
+ first_img_url = ''
86
+ if jm_view and the_type == 'dir':
87
+ imgs = self.get_jm_view_images(file_path)
88
+ if imgs:
89
+ first_img_url = imgs[0]
90
+
91
+ if name.endswith('.lnk'):
92
+ target_path = self.get_target_path(file_path)
93
+ return self.build_one_path_info(target_path, 'Link')
94
+
95
+ return {
96
+ "name": name,
97
+ 'path': file_path,
98
+ 'href': f'/?path={file_path}' if the_type == 'dir' else f'./download_file/{name}',
99
+ "size": size,
100
+ "ctime": time_str,
101
+ "type": the_type,
102
+ 'jm_view': jm_view,
103
+ 'first_img_url': first_img_url
104
+ }
105
+
106
+ def get_files_data(self, path):
107
+ files = list(filter(bool, map(self.build_one_path_info, self.files_of_dir_safe(path))))
108
+ self.current_path = path
109
+ files = self.sort_files(files)
110
+ return files
111
+
112
+ def sort_files(self, files: list):
113
+ def natural_key(item):
114
+ return [int(text) if text.isdigit() else text.lower()
115
+ for text in re.split(r'(\d+)', item['name'])]
116
+
117
+ # Split into groups
118
+ jm_albums = []
119
+ other_dirs = []
120
+ other_files = []
121
+
122
+ for f in files:
123
+ if f['jm_view']:
124
+ jm_albums.append(f)
125
+ elif f['type'] == 'dir':
126
+ other_dirs.append(f)
127
+ else:
128
+ other_files.append(f)
129
+
130
+ # Sort each group
131
+ jm_albums.sort(key=natural_key)
132
+ other_dirs.sort(key=natural_key)
133
+ other_files.sort(key=natural_key)
134
+
135
+ return jm_albums + other_dirs + other_files
136
+
137
+ def get_file_type(self, file_path):
138
+ if os.path.isfile(file_path):
139
+ the_type = 'file'
140
+ jm_view = self.check_dir_can_open_jm_view(common.of_dir_path(file_path))
141
+ else:
142
+ the_type = 'dir'
143
+ jm_view = self.check_dir_can_open_jm_view(file_path)
144
+ return jm_view, the_type
145
+
146
+ @staticmethod
147
+ def get_target_path(lnk_path: str) -> str:
148
+ try:
149
+ import pylnk3
150
+ lnk = pylnk3.parse(lnk_path)
151
+ return lnk.path.replace("\\", '/').replace("//", '/') # 获取目标文件/文件夹路径
152
+ except Exception as e:
153
+ return lnk_path
154
+
155
+ @staticmethod
156
+ def file_size_format(size, the_type):
157
+ if the_type == 'dir':
158
+ return '<DIR>'
159
+ else:
160
+ if size < 1024:
161
+ return '%i' % size + ' B'
162
+ elif 1024 < size <= 1048576:
163
+ return '%.1f' % float(size / 1024) + ' KB'
164
+ elif 1048576 < size <= 1073741824:
165
+ return '%.1f' % float(size / 1048576) + ' MB'
166
+ elif 1073741824 < size <= 1099511627776:
167
+ return '%.1f' % float(size / 1073741824) + ' GB'
168
+
169
+ def get_current_path(self):
170
+ return self.current_path