hiddifypanel 10.50.4__py3-none-any.whl → 10.50.6.dev0__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.
Files changed (48) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/drivers/user_driver.py +11 -7
  4. hiddifypanel/hutils/flask.py +5 -3
  5. hiddifypanel/hutils/network/net.py +22 -11
  6. hiddifypanel/hutils/proxy/shared.py +10 -3
  7. hiddifypanel/hutils/proxy/xray.py +1 -1
  8. hiddifypanel/hutils/proxy/xrayjson.py +11 -0
  9. hiddifypanel/models/config_enum.py +117 -114
  10. hiddifypanel/models/proxy.py +1 -0
  11. hiddifypanel/panel/admin/Actions.py +1 -1
  12. hiddifypanel/panel/admin/DomainAdmin.py +4 -3
  13. hiddifypanel/panel/admin/ProxyAdmin.py +1 -1
  14. hiddifypanel/panel/admin/SettingAdmin.py +2 -2
  15. hiddifypanel/panel/admin/templates/config.html +129 -1
  16. hiddifypanel/panel/commercial/restapi/v1/__init__.py +1 -1
  17. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +6 -0
  18. hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +2 -2
  19. hiddifypanel/panel/commercial/restapi/v2/user/configs_api.py +9 -1
  20. hiddifypanel/panel/commercial/telegrambot/__init__.py +1 -1
  21. hiddifypanel/panel/common.py +3 -1
  22. hiddifypanel/panel/custom_widgets.py +3 -0
  23. hiddifypanel/panel/hiddify.py +7 -4
  24. hiddifypanel/panel/init_db.py +58 -2
  25. hiddifypanel/panel/usage.py +30 -16
  26. hiddifypanel/panel/user/user.py +38 -0
  27. hiddifypanel/templates/fake.html +4 -0
  28. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  29. hiddifypanel/translations/en/LC_MESSAGES/messages.po +21 -2
  30. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  31. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +19 -2
  32. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  33. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +19 -2
  34. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  35. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +19 -2
  36. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  37. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +19 -2
  38. hiddifypanel/translations.i18n/en.json +10 -1
  39. hiddifypanel/translations.i18n/fa.json +10 -1
  40. hiddifypanel/translations.i18n/pt.json +10 -1
  41. hiddifypanel/translations.i18n/ru.json +10 -1
  42. hiddifypanel/translations.i18n/zh.json +10 -1
  43. {hiddifypanel-10.50.4.dist-info → hiddifypanel-10.50.6.dev0.dist-info}/METADATA +1 -1
  44. {hiddifypanel-10.50.4.dist-info → hiddifypanel-10.50.6.dev0.dist-info}/RECORD +48 -48
  45. {hiddifypanel-10.50.4.dist-info → hiddifypanel-10.50.6.dev0.dist-info}/WHEEL +1 -1
  46. {hiddifypanel-10.50.4.dist-info → hiddifypanel-10.50.6.dev0.dist-info}/LICENSE.md +0 -0
  47. {hiddifypanel-10.50.4.dist-info → hiddifypanel-10.50.6.dev0.dist-info}/entry_points.txt +0 -0
  48. {hiddifypanel-10.50.4.dist-info → hiddifypanel-10.50.6.dev0.dist-info}/top_level.txt +0 -0
@@ -26,7 +26,8 @@
26
26
 
27
27
 
28
28
  <div class="card">
29
- <div class="card-header"><input id="search_settings" type="text" class="form-control" placeholder="{{_(" Search Settings")}}">
29
+ <div class="card-header"><input id="search_settings" type="text" class="form-control" placeholder="{{_(" Search
30
+ Settings")}}">
30
31
  </div>
31
32
  <div class="card-body">
32
33
  <div class="row">
@@ -81,6 +82,133 @@
81
82
 
82
83
  {% block tail %}
83
84
  {{super()}}
85
+ <link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/42.0.2/ckeditor5.css">
86
+ <style>
87
+ .ck.ck-editor {
88
+ color: black !important;
89
+ }
90
+ </style>
91
+ <script src="https://cdn.ckeditor.com/ckeditor5/42.0.2/ckeditor5.js"></script>
92
+
93
+ <script type="importmap">
94
+ {
95
+ "imports": {
96
+ "ckeditor5": "https://cdn.ckeditor.com/ckeditor5/42.0.2/ckeditor5.js",
97
+ "ckeditor5/": "https://cdn.ckeditor.com/ckeditor5/42.0.2/"
98
+ }
99
+ }
100
+ </script>
101
+ <script type="module">
102
+ import {
103
+ ClassicEditor,
104
+ AccessibilityHelp,
105
+ Autosave,
106
+ BalloonToolbar,
107
+ Bold,
108
+ Code,
109
+ Essentials,
110
+ FontBackgroundColor,
111
+ FontColor,
112
+ FontFamily,
113
+ FontSize,
114
+ FullPage,
115
+ GeneralHtmlSupport,
116
+ Highlight,
117
+ HtmlComment,
118
+ HtmlEmbed,
119
+ Italic,
120
+ Paragraph,
121
+ SelectAll,
122
+ ShowBlocks,
123
+ SourceEditing,
124
+ SpecialCharacters,
125
+ Strikethrough,
126
+ ImageBlock,
127
+ ImageInsert,
128
+ ImageInsertViaUrl,
129
+ ImageToolbar,
130
+
131
+ Underline,
132
+ Undo
133
+ } from 'ckeditor5';
134
+
135
+ const editorConfig = {
136
+ toolbar: {
137
+ items: [
138
+ 'undo',
139
+ 'redo',
140
+ '|',
141
+ 'bold',
142
+ 'italic',
143
+ 'underline',
144
+ 'strikethrough',
145
+ 'code',
146
+ 'insertImage',
147
+ '|',
148
+ 'fontSize',
149
+ 'fontColor',
150
+ 'fontBackgroundColor',
151
+ '|',
152
+ 'sourceEditing',
153
+
154
+ ],
155
+ shouldNotGroupWhenFull: false
156
+ },
157
+ plugins: [
158
+ AccessibilityHelp,
159
+ Autosave,
160
+ BalloonToolbar,
161
+ Bold,
162
+ Code,
163
+ Essentials,
164
+ FontBackgroundColor,
165
+ FontColor,
166
+ FontFamily,
167
+ FontSize,
168
+ FullPage,
169
+ GeneralHtmlSupport,
170
+ Highlight,
171
+ HtmlComment,
172
+ HtmlEmbed,
173
+ Italic,
174
+ Paragraph,
175
+ SelectAll,
176
+ ShowBlocks,
177
+ SourceEditing,
178
+ ImageBlock,
179
+ ImageInsertViaUrl,
180
+
181
+ Strikethrough,
182
+ Underline,
183
+ Undo
184
+ ],
185
+ balloonToolbar: ['bold', 'italic'],
186
+ fontFamily: {
187
+ supportAllValues: true
188
+ },
189
+ fontSize: {
190
+ options: [10, 12, 14, 'default', 18, 20, 22],
191
+ supportAllValues: true
192
+ },
193
+ htmlSupport: {
194
+ allow: [
195
+ {
196
+ name: /^.*$/,
197
+ styles: true,
198
+ attributes: true,
199
+ classes: true
200
+ }
201
+ ]
202
+ },
203
+
204
+ placeholder: 'Type or paste your content here!'
205
+ };
206
+
207
+ ClassicEditor.create(document.querySelector('.ckeditor'), editorConfig);
208
+
209
+
210
+ </script>
211
+
84
212
  <script>
85
213
  // $("fieldset .form-group").hide()
86
214
 
@@ -5,7 +5,7 @@ from marshmallow import Schema, fields
5
5
 
6
6
  from apiflask import APIBlueprint
7
7
  from flask_restful import Api
8
- from .tgbot import bot, register_bot, TGBotResource
8
+ from .tgbot import bot, register_bot, register_bot_cached, TGBotResource
9
9
  from . import tgbot
10
10
  from .tgmsg import SendMsgResource
11
11
  from .resources import *
@@ -5,6 +5,7 @@ from flask_restful import Resource
5
5
 
6
6
  from hiddifypanel.models import *
7
7
  from hiddifypanel import Events
8
+ from hiddifypanel.cache import cache
8
9
  logger = telebot.logger
9
10
 
10
11
 
@@ -17,6 +18,11 @@ bot = telebot.TeleBot("", parse_mode="HTML", threaded=False, exception_handler=E
17
18
  bot.username = ''
18
19
 
19
20
 
21
+ @cache.cache(1000)
22
+ def register_bot_cached(set_hook=False, remove_hook=False):
23
+ return register_bot(set_hook, remove_hook)
24
+
25
+
20
26
  def register_bot(set_hook=False, remove_hook=False):
21
27
  try:
22
28
  global bot
@@ -35,8 +35,8 @@ class UserApi(MethodView):
35
35
  for field in User.__table__.columns.keys(): # type: ignore
36
36
  if field in ['id', 'expiry_time']:
37
37
  continue
38
- if field not in data:
39
- data[field] = getattr(user, field)
38
+ # if field in data:
39
+ # setattr(user, field, data[field])
40
40
  data['old_uuid'] = uuid
41
41
  user_driver.remove_client(user)
42
42
  dbuser = User.add_or_update(**data) or abort(502, "Unknown issue! User is not patched")
@@ -108,7 +108,15 @@ class AllConfigsAPI(MethodView):
108
108
  )
109
109
  )
110
110
 
111
- # Add Singbox: SSh
111
+ if hconfig(ConfigEnum.wireguard_enable):
112
+ items.append(
113
+ create_item(
114
+ "Wireguard", "Wireguard", "", "", "", "",
115
+ # f"{base_url}singbox.json?name={c['db_domain'].alias or c['db_domain'].domain}-{c['asn']}&asn={c['asn']}&mode={c['mode']}"
116
+ f"{base_url}wireguard/#{config_name}"
117
+ )
118
+ )
119
+ # Add Singbox: SSh
112
120
  if hconfig(ConfigEnum.sub_singbox_ssh_enable) and hconfig(ConfigEnum.ssh_server_enable):
113
121
  items.append(
114
122
  create_item(
@@ -1,4 +1,4 @@
1
- from hiddifypanel.panel.commercial.restapi.v1 import bot, register_bot
1
+ from hiddifypanel.panel.commercial.restapi.v1 import bot, register_bot, register_bot_cached
2
2
 
3
3
  from . import Usage
4
4
  from . import information
@@ -10,6 +10,7 @@ import hiddifypanel.auth as auth
10
10
  from hiddifypanel.auth import current_account
11
11
  from apiflask import APIFlask, HTTPError, abort
12
12
  from hiddifypanel import hutils
13
+ from loguru import logger
13
14
 
14
15
 
15
16
  def init_app(app: APIFlask):
@@ -36,6 +37,7 @@ def init_app(app: APIFlask):
36
37
 
37
38
  @app.errorhandler(Exception)
38
39
  def internal_server_error(e):
40
+ logger.exception(e)
39
41
  if isinstance(e, Exception):
40
42
  if hutils.flask.is_api_call(request.path):
41
43
  return {
@@ -181,4 +183,4 @@ def init_app(app: APIFlask):
181
183
  with app.app_context():
182
184
  import hiddifypanel.panel.commercial.telegrambot as telegrambot
183
185
  if (not telegrambot.bot) or (not telegrambot.bot.username): # type: ignore
184
- telegrambot.register_bot(set_hook=True)
186
+ telegrambot.register_bot_cached(set_hook=True)
@@ -47,6 +47,8 @@ class LastResetField(IntegerField):
47
47
 
48
48
 
49
49
  class CKTextAreaWidget(TextArea):
50
+ extra_js = ['//cdn.ckeditor.com/4.6.0/standard/ckeditor.js']
51
+
50
52
  def __call__(self, field, **kwargs):
51
53
  if kwargs.get('class'):
52
54
  kwargs['class'] += ' ckeditor'
@@ -56,6 +58,7 @@ class CKTextAreaWidget(TextArea):
56
58
 
57
59
 
58
60
  class CKTextAreaField(TextAreaField):
61
+ extra_js = ['//cdn.ckeditor.com/4.6.0/standard/ckeditor.js']
59
62
  widget = CKTextAreaWidget()
60
63
 
61
64
 
@@ -110,17 +110,20 @@ def reinstall_action(complete_install=False, domain_changed=False, do_update=Fal
110
110
  def check_need_reset(old_configs, do=False):
111
111
  restart_mode = ApplyMode.nothing
112
112
  for c in old_configs:
113
+ if c.apply_mode == ApplyMode.nothing:
114
+ continue
113
115
  # c=ConfigEnum(c)
114
- if old_configs[c] != hconfig(c) and c.apply_mode != ApplyMode.nothing:
115
- if restart_mode != ApplyMode.restart:
116
- restart_mode = c.apply_mode
116
+ if restart_mode == ApplyMode.reinstall:
117
+ break
118
+ if old_configs[c] != hconfig(c):
119
+ restart_mode = c.apply_mode
117
120
  if old_configs[ConfigEnum.proxy_path_admin] != hconfig(ConfigEnum.proxy_path_admin):
118
121
  g.new_proxy_path = hconfig(ConfigEnum.proxy_path_admin)
119
122
  g.force_proxy_path = g.proxy_path
120
123
  # do_full_install=old_config[ConfigEnum.telegram_lib]!=hconfig(ConfigEnum.telegram_lib)
121
124
  if old_configs[ConfigEnum.package_mode] != hconfig(ConfigEnum.package_mode):
122
125
  return reinstall_action(do_update=True)
123
- if not (do and restart_mode == ApplyMode.restart):
126
+ if not (do and restart_mode == ApplyMode.reinstall):
124
127
  return hutils.flask.flash_config_success(restart_mode=restart_mode, domain_changed=False)
125
128
 
126
129
  return reinstall_action(complete_install=True, domain_changed=False)
@@ -12,12 +12,55 @@ from hiddifypanel.models import *
12
12
  from hiddifypanel.panel import hiddify
13
13
  from hiddifypanel.database import db, db_execute
14
14
  from flask import g
15
- from sqlalchemy import text
15
+ from sqlalchemy import func, text
16
16
  from loguru import logger
17
17
  MAX_DB_VERSION = 100
18
18
 
19
19
 
20
- def _v88(child_id):
20
+ def _v91(child_id):
21
+ db.session.bulk_save_objects(get_proxy_rows_v1())
22
+
23
+
24
+ def _v90(child_id):
25
+ result = (
26
+ db.session.query(
27
+ DailyUsage.child_id,
28
+ DailyUsage.admin_id,
29
+ DailyUsage.date,
30
+ func.max(DailyUsage.online).label('online'),
31
+ func.sum(DailyUsage.usage).label('usage'),
32
+ func.count(DailyUsage.usage).label('count'),
33
+ )
34
+ .group_by(DailyUsage.child_id, DailyUsage.admin_id, DailyUsage.date)
35
+ .all()
36
+ )
37
+
38
+ for r in result:
39
+ if r.count > 1:
40
+ # Delete existing records for this group
41
+ db.session.query(DailyUsage).filter(
42
+ DailyUsage.child_id == r.child_id,
43
+ DailyUsage.admin_id == r.admin_id,
44
+ DailyUsage.date == r.date
45
+ ).delete()
46
+
47
+ # Add the aggregated record
48
+ new_record = DailyUsage(
49
+ child_id=r.child_id,
50
+ admin_id=r.admin_id,
51
+ date=r.date,
52
+ online=r.online,
53
+ usage=r.usage
54
+ )
55
+ db.session.add(new_record)
56
+
57
+ # Commit the changes to the database
58
+ db.session.commit()
59
+
60
+
61
+ def _v89(child_id):
62
+ set_hconfig(ConfigEnum.path_splithttp, hutils.random.get_random_string(7, 15))
63
+ set_hconfig(ConfigEnum.splithttp_enable, False)
21
64
  pass
22
65
 
23
66
 
@@ -471,6 +514,9 @@ def get_proxy_rows_v1():
471
514
  "httpupgrade direct vless",
472
515
  # "httpupgrade direct trojan",
473
516
  "httpupgrade direct vmess",
517
+ "splithttp direct vless",
518
+ "splithttp direct trojan",
519
+ "splithttp direct vmess",
474
520
  "tcp direct vless",
475
521
  "tcp direct trojan",
476
522
  "tcp direct vmess",
@@ -487,6 +533,11 @@ def get_proxy_rows_v1():
487
533
  "httpupgrade relay vless",
488
534
  # "httpupgrade relay trojan",
489
535
  "httpupgrade relay vmess",
536
+
537
+ "splithttp relay vless",
538
+ "splithttp relay trojan",
539
+ "splithttp relay vmess",
540
+
490
541
  "tcp relay vless",
491
542
  "tcp relay trojan",
492
543
  "tcp relay vmess",
@@ -506,6 +557,11 @@ def get_proxy_rows_v1():
506
557
  "httpupgrade CDN vless",
507
558
  # "httpupgrade CDN trojan",
508
559
  "httpupgrade CDN vmess",
560
+
561
+ "splithttp CDN vless",
562
+ "splithttp CDN trojan",
563
+ "splithttp CDN vmess",
564
+
509
565
  "grpc CDN vless",
510
566
  "grpc CDN trojan",
511
567
  "grpc CDN vmess",
@@ -7,14 +7,24 @@ from hiddifypanel.drivers import user_driver
7
7
  from hiddifypanel.models import *
8
8
  from hiddifypanel.panel import hiddify
9
9
  from hiddifypanel.database import db
10
- from hiddifypanel import hutils
10
+ from hiddifypanel import cache, hutils
11
11
 
12
12
  to_gig_d = 1024**3
13
13
 
14
14
 
15
15
  def update_local_usage():
16
- res = user_driver.get_users_usage(reset=True)
17
- return _add_users_usage(res, child_id=0)
16
+ lock_key = "lock-update-local-usage"
17
+ if not cache.redis_client.set(lock_key, "locked", nx=True, ex=600):
18
+ return {"msg": "last update task is not finished yet."}
19
+ try:
20
+ res = user_driver.get_users_usage(reset=True)
21
+ # cache.redis_client.delete(lock_key)
22
+ cache.redis_client.set(lock_key, "locked", nx=False, ex=60)
23
+ return _add_users_usage(res, child_id=0)
24
+ except Exception as e:
25
+ cache.redis_client.set(lock_key, "locked", nx=False, ex=60)
26
+ raise
27
+ return {"msg": f"Exception in update usage: {e}"}
18
28
 
19
29
  # return {"status": 'success', "comments":res}
20
30
 
@@ -53,26 +63,30 @@ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
53
63
 
54
64
  daily_usage = {}
55
65
  today = datetime.date.today()
66
+ changes = False
56
67
  for adm in AdminUser.query.all():
57
68
  daily_usage[adm.id] = DailyUsage.query.filter(DailyUsage.date == today, DailyUsage.admin_id == adm.id, DailyUsage.child_id == child_id).first()
58
- if not daily_usage[adm.id]:
69
+ if daily_usage[adm.id] is None:
59
70
  daily_usage[adm.id] = DailyUsage(admin_id=adm.id, child_id=child_id)
60
71
  db.session.add(daily_usage[adm.id])
72
+ changes = True
61
73
  daily_usage[adm.id].online = User.query.filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
62
-
74
+ # if changes:
75
+ # db.session.commit()
63
76
  _reset_priodic_usage()
64
77
 
65
- userDetails = {p.user_id: p for p in UserDetail.query.filter(UserDetail.child_id == child_id).all()}
78
+ # userDetails = {p.user_id: p for p in UserDetail.query.filter(UserDetail.child_id == child_id).all()}
66
79
  for user, uinfo in users_usage_data.items():
67
80
  usage_bytes = uinfo['usage']
68
81
 
69
82
  # UserDetails things
70
- detail = userDetails.get(user.id)
71
- if not detail:
72
- detail = UserDetail(user_id=user.id, child_id=child_id)
73
- db.session.add(detail)
74
- if uinfo['devices'] != detail.connected_devices:
75
- detail.connected_devices = uinfo['devices']
83
+ # detail = UserDetail(user_id=user.id, child_id=child_id)
84
+ # detail = userDetails.get(user.id)
85
+ # if not detail:
86
+ # detail = UserDetail(user_id=user.id, child_id=child_id)
87
+ # db.session.add(detail)
88
+ # if uinfo['devices'] != detail.connected_devices:
89
+ # detail.connected_devices = uinfo['devices']
76
90
 
77
91
  # Enable the user if isn't already
78
92
  if not before_enabled_users[user.uuid] and user.is_active:
@@ -99,12 +113,12 @@ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
99
113
  # detail.current_usage_GB = in_gig
100
114
  else:
101
115
  user.current_usage += in_bytes
102
- detail.current_usage = detail.current_usage or 0
103
- detail.current_usage += in_bytes
116
+ # detail.current_usage = detail.current_usage or 0
117
+ # detail.current_usage += in_bytes
104
118
 
105
119
  # Change last online time of the user
106
120
  user.last_online = datetime.datetime.now()
107
- detail.last_online = datetime.datetime.now()
121
+ # detail.last_online = datetime.datetime.now()
108
122
 
109
123
  # Set start date of user to the current datetime if it hasn't been set already
110
124
  if user.start_date is None:
@@ -142,7 +156,7 @@ def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
142
156
  if not sync and hutils.node.is_child():
143
157
  hutils.node.child.sync_users_usage_with_parent()
144
158
 
145
- return {"status": 'success', "comments": res, "date": datetime.datetime.now()}
159
+ return {"status": 'success', "comments": res, "date": hutils.convert.time_to_json(datetime.datetime.now())}
146
160
 
147
161
 
148
162
  def send_bot_message(user):
@@ -73,6 +73,44 @@ class UserView(FlaskView):
73
73
  '''Returns singbox client JSON config (ssh)'''
74
74
  return self.singbox_ssh_imp()
75
75
 
76
+ @route("/wireguard/")
77
+ @route("/wireguard")
78
+ @login_required(roles={Role.user})
79
+ def wireguard(self):
80
+ '''Returns wireguard client config'''
81
+ c = get_common_data(g.account.uuid, 'new')
82
+ wireguards = []
83
+ servers = set()
84
+ for pinfo in hutils.proxy.get_valid_proxies(c['domains']):
85
+ if pinfo['proto'] != ProxyProto.wireguard:
86
+ continue
87
+ wireguards.append(pinfo)
88
+
89
+ servers.add(pinfo['server'])
90
+
91
+ if not len(wireguards):
92
+ abort(404)
93
+ wg = wireguards[0]
94
+ addrs = f"{wg['wg_ipv4']}/32"
95
+ if wg['wg_ipv6']:
96
+ addrs += f", {wg['wg_ipv6']}/128"
97
+ resp = f"""
98
+ [Interface]
99
+ PrivateKey = {wg['wg_pk']}
100
+ Address = {addrs}
101
+ DNS = 1.1.1.1
102
+ MTU = 1390
103
+
104
+ [Peer]
105
+ PublicKey = {wg['wg_pub']}
106
+ PresharedKey = {wg['wg_psk']}
107
+ AllowedIPs = 0.0.0.0/1, 128.0.0.0/1, ::/1, 8000::/1
108
+ Endpoint = {next(iter(servers))}:61339 #{servers}
109
+ """
110
+ return add_headers(resp, c)
111
+
112
+ # return self.singbox_ssh_imp()
113
+
76
114
  @route("/clash/")
77
115
  @route("/clash")
78
116
  @login_required(roles={Role.user})
@@ -212,6 +212,8 @@
212
212
  {{_("config.grpc_enable.description")}}
213
213
  {{_("config.httpupgrade_enable.label")}}
214
214
  {{_("config.httpupgrade_enable.description")}}
215
+ {{_("config.splithttp_enable.label")}}
216
+ {{_("config.splithttp_enable.description")}}
215
217
  {{_("config.vless_enable.label")}}
216
218
  {{_("config.vless_enable.description")}}
217
219
  {{_("config.trojan_enable.label")}}
@@ -248,6 +250,8 @@
248
250
  {{_("config.path_v2ray.description")}}
249
251
  {{_("config.path_ss.label")}}
250
252
  {{_("config.path_ss.description")}}
253
+ {{_("config.path_splithttp.label")}}
254
+ {{_("config.path_splithttp.description")}}
251
255
  {{_("config.path_httpupgrade.label")}}
252
256
  {{_("config.path_httpupgrade.description")}}
253
257
  {{_("config.path_ws.label")}}
@@ -2,8 +2,12 @@
2
2
  msgid ""
3
3
  msgstr ""
4
4
 
5
- msgid " Search Settings"
6
- msgstr " Search Settings"
5
+ msgid ""
6
+ " Search\n"
7
+ " Settings"
8
+ msgstr ""
9
+ " Search\n"
10
+ " Settings"
7
11
 
8
12
  msgid "%(count)s records were successfully disabled."
9
13
  msgstr "%(count)s records were successfully disabled."
@@ -670,6 +674,9 @@ msgstr "Select this option to restore All Users"
670
674
  msgid "Root"
671
675
  msgstr "Root"
672
676
 
677
+ msgid "Russia"
678
+ msgstr "Russia"
679
+
673
680
  msgid "Save"
674
681
  msgstr "Save"
675
682
 
@@ -1638,6 +1645,12 @@ msgstr "should be random"
1638
1645
  msgid "config.path_httpupgrade.label"
1639
1646
  msgstr "ℹ️ HTTP Upgrade Path"
1640
1647
 
1648
+ msgid "config.path_splithttp.description"
1649
+ msgstr "config.path_splithttp.description"
1650
+
1651
+ msgid "config.path_splithttp.label"
1652
+ msgstr "config.path_splithttp.label"
1653
+
1641
1654
  msgid "config.path_ss.description"
1642
1655
  msgstr "Shadowsocks Path in the Links"
1643
1656
 
@@ -1858,6 +1871,12 @@ msgstr ""
1858
1871
  msgid "config.speed_test.label"
1859
1872
  msgstr "🚀 Speed Test"
1860
1873
 
1874
+ msgid "config.splithttp_enable.description"
1875
+ msgstr "config.splithttp_enable.description"
1876
+
1877
+ msgid "config.splithttp_enable.label"
1878
+ msgstr "config.splithttp_enable.label"
1879
+
1861
1880
  msgid "config.ssfaketls.description"
1862
1881
  msgstr ""
1863
1882
  "Shadowsocks FakeTLS is a simple obfusacting tool that encapsulate the date "
@@ -2,8 +2,10 @@
2
2
  msgid ""
3
3
  msgstr ""
4
4
 
5
- msgid " Search Settings"
6
- msgstr " تنظیمات جستجو"
5
+ msgid ""
6
+ " Search\n"
7
+ " Settings"
8
+ msgstr ""
7
9
 
8
10
  msgid "%(count)s records were successfully disabled."
9
11
  msgstr "%(count)s رکورد با موفقیت غیرفعال شد."
@@ -654,6 +656,9 @@ msgstr "برای بازگرداندن کاربران از این گزینه اس
654
656
  msgid "Root"
655
657
  msgstr "ریشه"
656
658
 
659
+ msgid "Russia"
660
+ msgstr ""
661
+
657
662
  msgid "Save"
658
663
  msgstr "ذخیره"
659
664
 
@@ -1635,6 +1640,12 @@ msgstr "باید تصادفی باشد"
1635
1640
  msgid "config.path_httpupgrade.label"
1636
1641
  msgstr "ℹ️ مسیر ارتقاء HTTP"
1637
1642
 
1643
+ msgid "config.path_splithttp.description"
1644
+ msgstr ""
1645
+
1646
+ msgid "config.path_splithttp.label"
1647
+ msgstr ""
1648
+
1638
1649
  msgid "config.path_ss.description"
1639
1650
  msgstr "مسیر شدوساکس در لینکها"
1640
1651
 
@@ -1859,6 +1870,12 @@ msgstr ""
1859
1870
  msgid "config.speed_test.label"
1860
1871
  msgstr "🚀 تست سرعت"
1861
1872
 
1873
+ msgid "config.splithttp_enable.description"
1874
+ msgstr ""
1875
+
1876
+ msgid "config.splithttp_enable.label"
1877
+ msgstr ""
1878
+
1862
1879
  msgid "config.ssfaketls.description"
1863
1880
  msgstr ""
1864
1881
  "شادوساکس FakeTLS یک روش مبهم سازی ساده هست که دیتا را در بسته TLS کپسوله "
@@ -2,8 +2,10 @@
2
2
  msgid ""
3
3
  msgstr ""
4
4
 
5
- msgid " Search Settings"
6
- msgstr " Configurações de pesquisa"
5
+ msgid ""
6
+ " Search\n"
7
+ " Settings"
8
+ msgstr ""
7
9
 
8
10
  msgid "%(count)s records were successfully disabled."
9
11
  msgstr "%(count)s registros foram desativados com sucesso."
@@ -609,6 +611,9 @@ msgstr "Selecione esta opção para restaurar todos os usuários"
609
611
  msgid "Root"
610
612
  msgstr "Raíz"
611
613
 
614
+ msgid "Russia"
615
+ msgstr ""
616
+
612
617
  msgid "Save"
613
618
  msgstr "Salvar"
614
619
 
@@ -1568,6 +1573,12 @@ msgstr ""
1568
1573
  msgid "config.path_httpupgrade.label"
1569
1574
  msgstr ""
1570
1575
 
1576
+ msgid "config.path_splithttp.description"
1577
+ msgstr ""
1578
+
1579
+ msgid "config.path_splithttp.label"
1580
+ msgstr ""
1581
+
1571
1582
  msgid "config.path_ss.description"
1572
1583
  msgstr "Caminho Shadowsocks nos Links"
1573
1584
 
@@ -1785,6 +1796,12 @@ msgstr ""
1785
1796
  msgid "config.speed_test.label"
1786
1797
  msgstr "🚀 Teste de velocidade"
1787
1798
 
1799
+ msgid "config.splithttp_enable.description"
1800
+ msgstr ""
1801
+
1802
+ msgid "config.splithttp_enable.label"
1803
+ msgstr ""
1804
+
1788
1805
  msgid "config.ssfaketls.description"
1789
1806
  msgstr ""
1790
1807
  "Shadowsocks FakeTLS é uma ferramenta de ofuscação simples que encapsula a "