plugin-jm-server 0.1.24__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.24 → plugin_jm_server-0.2.0}/PKG-INFO +18 -2
  2. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/README.md +17 -1
  3. plugin_jm_server-0.2.0/src/plugin_jm_server/__init__.py +3 -0
  4. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/app.py +95 -7
  5. plugin_jm_server-0.2.0/src/plugin_jm_server/files.py +170 -0
  6. plugin_jm_server-0.2.0/src/plugin_jm_server/static/css/index.css +729 -0
  7. plugin_jm_server-0.2.0/src/plugin_jm_server/static/css/index_spa.css +556 -0
  8. plugin_jm_server-0.2.0/src/plugin_jm_server/static/css/style_photo.css +1 -0
  9. plugin_jm_server-0.2.0/src/plugin_jm_server/static/img/bg.jpg +0 -0
  10. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/common.js +78 -0
  11. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/index.js +317 -0
  12. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/index_spa.js +612 -0
  13. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/jquery.lazyload-2.0.js +444 -0
  14. plugin_jm_server-0.2.0/src/plugin_jm_server/static/js/jquery.photo-0.3.js +427 -0
  15. plugin_jm_server-0.2.0/src/plugin_jm_server/templates/index.html +191 -0
  16. plugin_jm_server-0.2.0/src/plugin_jm_server/templates/index_spa.html +118 -0
  17. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/jm_view.html +10 -3
  18. plugin_jm_server-0.2.0/src/plugin_jm_server/templates/m_index.html +187 -0
  19. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/PKG-INFO +18 -2
  20. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/SOURCES.txt +5 -0
  21. plugin_jm_server-0.1.24/src/plugin_jm_server/__init__.py +0 -3
  22. plugin_jm_server-0.1.24/src/plugin_jm_server/files.py +0 -119
  23. plugin_jm_server-0.1.24/src/plugin_jm_server/static/css/index.css +0 -200
  24. plugin_jm_server-0.1.24/src/plugin_jm_server/static/css/style_photo.css +0 -1
  25. plugin_jm_server-0.1.24/src/plugin_jm_server/static/img/bg.jpg +0 -0
  26. plugin_jm_server-0.1.24/src/plugin_jm_server/static/js/common.js +0 -49
  27. plugin_jm_server-0.1.24/src/plugin_jm_server/static/js/index.js +0 -95
  28. plugin_jm_server-0.1.24/src/plugin_jm_server/templates/index.html +0 -100
  29. plugin_jm_server-0.1.24/src/plugin_jm_server/templates/m_index.html +0 -92
  30. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/setup.cfg +0 -0
  31. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/setup.py +0 -0
  32. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/driver.py +0 -0
  33. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/all.min.css +0 -0
  34. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/bootstrap.css +0 -0
  35. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/download_error.css +0 -0
  36. {plugin_jm_server-0.1.24 → 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.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_index.css +0 -0
  38. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_login.css +0 -0
  39. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/m_upload.css +0 -0
  40. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/h5/normalize.css +0 -0
  41. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/login.css +0 -0
  42. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/css/upload.css +0 -0
  43. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/img/m_bg.jpeg +0 -0
  44. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/h5/m_index.js +0 -0
  45. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/h5/m_upload.js +0 -0
  46. {plugin_jm_server-0.1.24 → 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.24 → 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.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/js/upload.js +0 -0
  49. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/webfonts/fa-regular-400.woff2 +0 -0
  50. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/static/webfonts/fa-solid-900.woff2 +0 -0
  51. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/download_error.html +0 -0
  52. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/login.html +0 -0
  53. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_download_error.html +0 -0
  54. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_jm_view.html +0 -0
  55. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_login.html +0 -0
  56. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/m_upload.html +0 -0
  57. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server/templates/upload.html +0 -0
  58. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/dependency_links.txt +0 -0
  59. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/requires.txt +0 -0
  60. {plugin_jm_server-0.1.24 → plugin_jm_server-0.2.0}/src/plugin_jm_server.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin_jm_server
3
- Version: 0.1.24
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
@@ -138,12 +138,28 @@ op.wait_all_plugins_finish()
138
138
  # 效果图(文件浏览、整章看图)
139
139
 
140
140
  ## 1. 电脑浏览器访问
141
+
142
+ ### 登录页
141
143
  ![](images/3.png)
144
+
145
+ ### 文件夹列表页
142
146
  ![](images/4.png)
147
+ ![](images/9.png)
148
+
149
+ ### 看本模式
143
150
  ![](images/5.png)
144
151
 
152
+ ### 文件夹&看本 二合一模式
153
+ ![](images/8.png)
154
+
145
155
  ## 2. 手机浏览器访问
156
+
157
+ ### 登录页
146
158
  ![](images/1.jpeg)
147
- ![](images/2.jpeg)
159
+
160
+ ### 文件夹列表页
161
+ ![](images/2.png)
162
+
163
+ ### 看本模式
148
164
  ![](images/7.jpeg)
149
165
 
@@ -102,12 +102,28 @@ op.wait_all_plugins_finish()
102
102
  # 效果图(文件浏览、整章看图)
103
103
 
104
104
  ## 1. 电脑浏览器访问
105
+
106
+ ### 登录页
105
107
  ![](images/3.png)
108
+
109
+ ### 文件夹列表页
106
110
  ![](images/4.png)
111
+ ![](images/9.png)
112
+
113
+ ### 看本模式
107
114
  ![](images/5.png)
108
115
 
116
+ ### 文件夹&看本 二合一模式
117
+ ![](images/8.png)
118
+
109
119
  ## 2. 手机浏览器访问
120
+
121
+ ### 登录页
110
122
  ![](images/1.jpeg)
111
- ![](images/2.jpeg)
123
+
124
+ ### 文件夹列表页
125
+ ![](images/2.png)
126
+
127
+ ### 看本模式
112
128
  ![](images/7.jpeg)
113
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
 
@@ -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