hiddifypanel 10.80.12.dev1__py3-none-any.whl → 10.85.0b1__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 (74) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +3 -3
  3. hiddifypanel/apps/asgi_app.py +1 -1
  4. hiddifypanel/apps/celery_app.py +2 -2
  5. hiddifypanel/apps/celery_app_flask.py +3 -0
  6. hiddifypanel/apps/wsgi_app.py +1 -1
  7. hiddifypanel/base.py +5 -5
  8. hiddifypanel/celery.py +68 -1
  9. hiddifypanel/database.py +62 -5
  10. hiddifypanel/drivers/singbox_api.py +2 -1
  11. hiddifypanel/drivers/user_driver.py +4 -1
  12. hiddifypanel/hutils/__init__.py +46 -14
  13. hiddifypanel/hutils/crypto.py +2 -1
  14. hiddifypanel/hutils/encode.py +1 -2
  15. hiddifypanel/hutils/flask.py +1 -1
  16. hiddifypanel/hutils/network/auto_ip_selector.py +15 -12
  17. hiddifypanel/hutils/network/cf_api.py +7 -2
  18. hiddifypanel/hutils/proxy/xrayjson.py +1 -0
  19. hiddifypanel/hutils/system.py +9 -8
  20. hiddifypanel/hutils/utils.py +2 -1
  21. hiddifypanel/models/admin.py +7 -5
  22. hiddifypanel/models/base_account.py +3 -3
  23. hiddifypanel/models/child.py +4 -4
  24. hiddifypanel/models/config.py +5 -5
  25. hiddifypanel/models/config_enum.py +3 -1
  26. hiddifypanel/models/domain.py +5 -5
  27. hiddifypanel/models/proxy.py +4 -2
  28. hiddifypanel/models/report.py +3 -3
  29. hiddifypanel/models/usage.py +2 -2
  30. hiddifypanel/models/user.py +3 -3
  31. hiddifypanel/panel/admin/templates/index.html +6 -6
  32. hiddifypanel/panel/cli.py +1 -1
  33. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +2 -3
  34. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
  35. hiddifypanel/panel/common.py +5 -1
  36. hiddifypanel/panel/common_bp/login.py +3 -2
  37. hiddifypanel/panel/hiddify.py +9 -9
  38. hiddifypanel/panel/hlogger.py +3 -1
  39. hiddifypanel/panel/init_db.py +71 -87
  40. hiddifypanel/panel/run_commander.py +3 -4
  41. hiddifypanel/panel/usage.py +10 -9
  42. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +19 -34
  43. hiddifypanel/panel/user/templates/base_xray_config.json.j2 +4 -2
  44. hiddifypanel/panel/user/templates/clash_config.yml +33 -3
  45. hiddifypanel/static/apps-icon/clash_verge_rev.ico +0 -0
  46. hiddifypanel/static/apps-icon/cmfa.ico +0 -0
  47. hiddifypanel/templates/master.html +1 -1
  48. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  49. hiddifypanel/translations/en/LC_MESSAGES/messages.po +13 -1
  50. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  51. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +13 -1
  52. hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
  53. hiddifypanel/translations/my/LC_MESSAGES/messages.po +0 -2
  54. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  55. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +13 -1
  56. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  57. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +13 -1
  58. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  59. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +13 -1
  60. hiddifypanel/translations.i18n/en.json +9 -1
  61. hiddifypanel/translations.i18n/fa.json +9 -1
  62. hiddifypanel/translations.i18n/fr.json +1 -0
  63. hiddifypanel/translations.i18n/my.json +4 -0
  64. hiddifypanel/translations.i18n/pt.json +9 -1
  65. hiddifypanel/translations.i18n/ru.json +9 -1
  66. hiddifypanel/translations.i18n/zh.json +9 -1
  67. hiddifypanel-10.85.0b1.dist-info/METADATA +331 -0
  68. {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b1.dist-info}/RECORD +120 -116
  69. {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b1.dist-info}/WHEEL +2 -1
  70. hiddifypanel-10.85.0b1.dist-info/entry_points.txt +2 -0
  71. hiddifypanel-10.85.0b1.dist-info/top_level.txt +1 -0
  72. hiddifypanel-10.80.12.dev1.dist-info/METADATA +0 -137
  73. hiddifypanel-10.80.12.dev1.dist-info/entry_points.txt +0 -3
  74. {hiddifypanel-10.80.12.dev1.dist-info → hiddifypanel-10.85.0b1.dist-info/licenses}/LICENSE.md +0 -0
@@ -3,10 +3,10 @@ import ipaddress
3
3
  import re
4
4
  from typing import Dict, List
5
5
  from flask import request
6
- from flask_babel import lazy_gettext as _
6
+
7
7
  from sqlalchemy.orm import backref
8
8
  from strenum import StrEnum
9
- from sqlalchemy_serializer import SerializerMixin
9
+
10
10
 
11
11
 
12
12
  from hiddifypanel.database import db
@@ -37,7 +37,7 @@ ShowDomain = db.Table('show_domain',
37
37
  )
38
38
 
39
39
 
40
- class Domain(db.Model, SerializerMixin):
40
+ class Domain(db.Model):
41
41
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
42
42
  child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0)
43
43
  domain = db.Column(db.String(200), nullable=True, unique=False)
@@ -161,9 +161,9 @@ class Domain(db.Model, SerializerMixin):
161
161
  def get_domains(cls, always_add_ip=False, always_add_all_domains=False) -> List['Domain']:
162
162
  from hiddifypanel import hutils
163
163
  domains = []
164
- domains = Domain.query.filter(Domain.mode == DomainType.sub_link_only, Domain.child_id == Child.current().id).all()
164
+ domains = db.session.query(Domain).filter(Domain.mode == DomainType.sub_link_only, Domain.child_id == Child.current().id).all()
165
165
  if not len(domains) or always_add_all_domains:
166
- domains = Domain.query.filter(Domain.mode.notin_([DomainType.fake, DomainType.reality])).all()
166
+ domains = db.session.query(Domain).filter(Domain.mode.notin_([DomainType.fake, DomainType.reality])).all()
167
167
 
168
168
  if len(domains) == 0 and request:
169
169
  domains = [Domain(domain=request.host)] # type: ignore
@@ -4,7 +4,7 @@ from enum import auto
4
4
  from sqlalchemy import Column, String, Integer, Boolean, Enum, ForeignKey
5
5
 
6
6
  from hiddifypanel.database import db
7
- from sqlalchemy_serializer import SerializerMixin
7
+
8
8
 
9
9
 
10
10
  class ProxyTransport(StrEnum):
@@ -59,7 +59,7 @@ class ProxyL3(StrEnum):
59
59
  custom = auto()
60
60
 
61
61
 
62
- class Proxy(db.Model, SerializerMixin): # type: ignore
62
+ class Proxy(db.Model): # type: ignore
63
63
  id = Column(Integer, primary_key=True, autoincrement=True)
64
64
  child_id = Column(Integer, ForeignKey('child.id'), default=0)
65
65
  name = Column(String(200), nullable=False, unique=False)
@@ -96,6 +96,8 @@ class Proxy(db.Model, SerializerMixin): # type: ignore
96
96
  dbproxy.enable = proxy['enable']
97
97
  dbproxy.name = proxy['name']
98
98
  dbproxy.proto = proxy['proto']
99
+ if proxy['transport']=="splithttp":
100
+ proxy['transport']="xhttp"
99
101
  dbproxy.transport = proxy['transport']
100
102
  dbproxy.cdn = proxy['cdn']
101
103
  dbproxy.l3 = proxy['l3']
@@ -2,10 +2,10 @@ import datetime
2
2
 
3
3
 
4
4
  from hiddifypanel.database import db
5
- from sqlalchemy_serializer import SerializerMixin
6
5
 
7
6
 
8
- class Report(db.Model, SerializerMixin):
7
+
8
+ class Report(db.Model):
9
9
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
10
10
  user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
11
11
  asn_id = db.Column(db.String(200), nullable=False, unique=False)
@@ -19,7 +19,7 @@ class Report(db.Model, SerializerMixin):
19
19
  details = db.relationship('ReportDetail', cascade="all,delete", backref='report', lazy='dynamic',)
20
20
 
21
21
 
22
- class ReportDetail(db.Model, SerializerMixin):
22
+ class ReportDetail(db.Model):
23
23
  report_id = db.Column(db.Integer, db.ForeignKey('report.id'), primary_key=True, )
24
24
  proxy_id = db.Column(db.Integer, db.ForeignKey('proxy.id'), primary_key=True, )
25
25
  ping = db.Column(db.Integer, default=-1)
@@ -6,10 +6,10 @@ from sqlalchemy import func
6
6
 
7
7
 
8
8
  from hiddifypanel.database import db
9
- from sqlalchemy_serializer import SerializerMixin
10
9
 
11
10
 
12
- class DailyUsage(db.Model, SerializerMixin):
11
+
12
+ class DailyUsage(db.Model):
13
13
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
14
14
  date = db.Column(db.Date, default=datetime.date.today(), index=True)
15
15
  usage = db.Column(db.BigInteger, default=0, nullable=False)
@@ -11,7 +11,7 @@ from hiddifypanel.database import db
11
11
  from hiddifypanel.models import Lang
12
12
  from hiddifypanel.models.base_account import BaseAccount
13
13
  from hiddifypanel.models.admin import AdminUser
14
- from sqlalchemy_serializer import SerializerMixin
14
+
15
15
 
16
16
  ONE_GIG = 1024 * 1024 * 1024
17
17
 
@@ -37,7 +37,7 @@ package_mode_dic = {
37
37
  }
38
38
 
39
39
 
40
- class UserDetail(db.Model, SerializerMixin):
40
+ class UserDetail(db.Model):
41
41
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
42
42
  user_id = db.Column(db.Integer, db.ForeignKey('user.id'), default=0, nullable=False)
43
43
  child_id = db.Column(db.Integer, db.ForeignKey('child.id'), default=0, nullable=False)
@@ -59,7 +59,7 @@ class UserDetail(db.Model, SerializerMixin):
59
59
  # return [] if not self.connected_devices else self.connected_devices.split(",")
60
60
 
61
61
 
62
- class User(BaseAccount, SerializerMixin):
62
+ class User(BaseAccount):
63
63
  """
64
64
  This is a model class for a user in a database that includes columns for their ID, UUID, name, online status,
65
65
  account expiration date, usage limit, package days, mode, start date, current usage, last reset time, and comment.
@@ -126,9 +126,9 @@
126
126
  {{info_box("ram","fa-solid fa-memory", _("RAM"),
127
127
  (stats['system']['ram_used']|round(3)) ~ " / " ~ (stats['system']['ram_total']|round(3)) ~ "GB (" ~((stats['system']['ram_used']*100/stats['system']['ram_total'])|int)~" %)",
128
128
  stats['system']['ram_used']*100/stats['system']['ram_total'],
129
- ('<i class="fa-solid fa-gauge"></i> '|safe) ~ stats['top5']['memory'][0][0] ~ " &rlm;"|safe ~ ((stats['top5']['memory'][0][1]*100/stats['system']['ram_total'])|int) ~ "% &rlm;"|safe~
130
- ('<i class="fa-solid fa-gauge"></i> '|safe) ~ stats['top5']['memory'][1][0] ~ " &rlm;"|safe ~ ((stats['top5']['memory'][1][1]*100/stats['system']['ram_total'])|int) ~ "% &rlm;"|safe~
131
- ('<i class="fa-solid fa-gauge"></i> '|safe) ~ stats['top5']['memory'][2][0] ~ " &rlm;"|safe ~ ((stats['top5']['memory'][2][1]*100/stats['system']['ram_total'])|int) ~ "% ",
129
+ ('<i class="fa-solid fa-gauge"></i> '|safe) ~ stats['top5']['ram'][0][0] ~ " &rlm;"|safe ~ ((stats['top5']['ram'][0][1]*100/stats['system']['ram_total'])|int) ~ "% &rlm;"|safe~
130
+ ('<i class="fa-solid fa-gauge"></i> '|safe) ~ stats['top5']['ram'][1][0] ~ " &rlm;"|safe ~ ((stats['top5']['ram'][1][1]*100/stats['system']['ram_total'])|int) ~ "% &rlm;"|safe~
131
+ ('<i class="fa-solid fa-gauge"></i> '|safe) ~ stats['top5']['ram'][2][0] ~ " &rlm;"|safe ~ ((stats['top5']['ram'][2][1]*100/stats['system']['ram_total'])|int) ~ "% ",
132
132
  coloring=True,
133
133
  color_class="bg-h-pink"
134
134
  )}}
@@ -253,9 +253,9 @@
253
253
  info_box("ram", "fa-solid fa-memory", "RAM",
254
254
  stats['system']['ram_used'].toFixed(1) + " / " + stats['system']['ram_total'].toFixed(1) + "GB (" + (stats['system']['ram_used'] * 100 / stats['system']['ram_total']).toFixed(0) + " %)",
255
255
  stats['system']['ram_used'] * 100 / stats['system']['ram_total'].toFixed(0),
256
- "<i class='fa-solid fa-gauge'></i> " + stats['top5']['memory'][0][0] + " &rlm;" + (stats['top5']['memory'][0][1] * 100 / stats['system']['ram_total']).toFixed(0) + "% &rlm; " +
257
- " <i class='fa-solid fa-gauge'></i> " + stats['top5']['memory'][1][0] + " &rlm;" + (stats['top5']['memory'][1][1] * 100 / stats['system']['ram_total']).toFixed(0) + "% &rlm; " +
258
- " <i class='fa-solid fa-gauge'></i> " + stats['top5']['memory'][2][0] + " &rlm;" + (stats['top5']['memory'][2][1] * 100 / stats['system']['ram_total']).toFixed(0) + "% ",
256
+ "<i class='fa-solid fa-gauge'></i> " + stats['top5']['ram'][0][0] + " &rlm;" + (stats['top5']['ram'][0][1] * 100 / stats['system']['ram_total']).toFixed(0) + "% &rlm; " +
257
+ " <i class='fa-solid fa-gauge'></i> " + stats['top5']['ram'][1][0] + " &rlm;" + (stats['top5']['ram'][1][1] * 100 / stats['system']['ram_total']).toFixed(0) + "% &rlm; " +
258
+ " <i class='fa-solid fa-gauge'></i> " + stats['top5']['ram'][2][0] + " &rlm;" + (stats['top5']['ram'][2][1] * 100 / stats['system']['ram_total']).toFixed(0) + "% ",
259
259
  true
260
260
  );
261
261
 
hiddifypanel/panel/cli.py CHANGED
@@ -47,7 +47,7 @@ def backup_task():
47
47
  if not bot.username:
48
48
  register_bot(True)
49
49
 
50
- for admin in AdminUser.query.filter(AdminUser.mode == AdminMode.super_admin, AdminUser.telegram_id is not None,AdminUser.telegram_id!=0).all():
50
+ for admin in db.session.query(AdminUser).filter(AdminUser.mode == AdminMode.super_admin, AdminUser.telegram_id is not None,AdminUser.telegram_id!=0).all():
51
51
  caption = ("Backup \n" + admin_links())
52
52
  with open(dst, 'rb') as document:
53
53
  try:
@@ -63,9 +63,8 @@ def register_bot(set_hook=False, remove_hook=False):
63
63
  if set_hook:
64
64
  bot.set_webhook(url=f"https://{domain}/{admin_proxy_path}/{user_secret}/api/v1/tgbot/")
65
65
  except Exception as e:
66
- print(e)
67
- import traceback
68
- traceback.print_stack()
66
+ logger.error(e)
67
+
69
68
 
70
69
 
71
70
  def init_app(app):
@@ -111,15 +111,17 @@ class AppAPI(MethodView):
111
111
  singbox_dto = self.__get_singbox_app_dto()
112
112
  # hiddifyng_dto = self.__get_hiddifyng_app_dto()
113
113
  v2rayng_dto = self.__get_v2rayng_app_dto()
114
+ cmfa_dto = self.__get_cmfa_app_dto()
114
115
  # hiddify_clash_android_dto = self.__get_hiddify_clash_android_app_dto()
115
116
  nekobox_dto = self.__get_nekobox_app_dto()
116
- apps_data += ([hiddify_next_dto, singbox_dto, v2rayng_dto, nekobox_dto])
117
+ apps_data += ([hiddify_next_dto, singbox_dto, v2rayng_dto, cmfa_dto, nekobox_dto])
117
118
  case Platform.windows:
118
119
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
120
+ clash_verge_rev_dto = self.__get_clash_verge_rev_app_dto()
119
121
  # hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
120
122
  # hiddifyn_dto = self.__get_hiddifyn_app_dto()
121
123
  v2rayn_dto = self.__get_v2rayn_app_dto()
122
- apps_data += ([hiddify_next_dto, v2rayn_dto])
124
+ apps_data += ([hiddify_next_dto, v2rayn_dto, clash_verge_rev_dto ])
123
125
  case Platform.ios:
124
126
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
125
127
  singbox_dto = self.__get_singbox_app_dto()
@@ -131,13 +133,15 @@ class AppAPI(MethodView):
131
133
  apps_data += ([hiddify_next_dto, singbox_dto, streisand_dto, stash_dto, shadowrocket_dto, foxray_dto, loon_dto])
132
134
  case Platform.linux:
133
135
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
136
+ clash_verge_rev_dto = self.__get_clash_verge_rev_app_dto()
134
137
  # hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
135
- apps_data += ([hiddify_next_dto])
138
+ apps_data += ([hiddify_next_dto, clash_verge_rev_dto ])
136
139
  case Platform.mac:
137
140
  hiddify_next_dto = self.__get_hiddify_next_app_dto()
138
141
  singbox_dto = self.__get_singbox_app_dto()
142
+ clash_verge_rev_dto = self.__get_clash_verge_rev_app_dto()
139
143
  # hiddify_clash_dto = self.__get_hiddify_clash_desktop_app_dto()
140
- apps_data += ([hiddify_next_dto, singbox_dto])
144
+ apps_data += ([hiddify_next_dto, singbox_dto, clash_verge_rev_dto ])
141
145
 
142
146
  return apps_data
143
147
 
@@ -168,11 +172,13 @@ class AppAPI(MethodView):
168
172
  stash_app_dto = self.__get_stash_app_dto()
169
173
  # hiddify_clash_app_dto = self.__get_hiddify_clash_desktop_app_dto()
170
174
  singbox_app_dto = self.__get_singbox_app_dto()
175
+ cmfa_app_dto = self.__get_cmfa_app_dto()
176
+ clash_verge_rev_app_dto = self.__get_clash_verge_rev_app_dto()
171
177
  hiddify_next_app_dto = self.__get_hiddify_next_app_dto()
172
178
  return [
173
179
  v2rayn_app_dto, v2rayng_app_dto,
174
180
  foxray_app_dto, shadowrocket_app_dto, streisand_app_dto,
175
- loon_app_dto, stash_app_dto, singbox_app_dto, hiddify_next_app_dto
181
+ loon_app_dto, stash_app_dto, singbox_app_dto, cmfa_app_dto, clash_verge_rev_app_dto, hiddify_next_app_dto
176
182
  ]
177
183
 
178
184
  def __get_app_icon_url(self, app_name):
@@ -182,6 +188,10 @@ class AppAPI(MethodView):
182
188
  url = base + static_url_for(filename='apps-icon/hiddify_next.ico')
183
189
  elif app_name == _('app.singbox.title'):
184
190
  url = base + static_url_for(filename='apps-icon/singbox.ico')
191
+ elif app_name == _('app.cmfa.title'):
192
+ url = base + static_url_for(filename='apps-icon/cmfa.ico')
193
+ elif app_name == _('app.clash_verge_rev.title'):
194
+ url = base + static_url_for(filename='apps-icon/clash_verge_rev.ico')
185
195
  elif app_name == _('app.hiddifyn.title'):
186
196
  url = base + static_url_for(filename='apps-icon/hiddifyn.ico')
187
197
  elif app_name == _('app.v2rayng.title'):
@@ -356,7 +366,7 @@ class AppAPI(MethodView):
356
366
  dto.description = _('app.singbox.description')
357
367
  dto.icon_url = self.__get_app_icon_url(_('app.singbox.title'))
358
368
  dto.guide_url = ''
359
- dto.deeplink = f'sing-box://import-remote-profile/?url={self.user_panel_url}'
369
+ dto.deeplink = f'sing-box://import-remote-profile/?url={self.user_panel_url}#{self.profile_title}'
360
370
 
361
371
  # availabe installatoin types
362
372
  installation_types = []
@@ -409,6 +419,66 @@ class AppAPI(MethodView):
409
419
  dto.install = install_dtos
410
420
  return dto
411
421
 
422
+ def __get_clash_verge_rev_app_dto(self):
423
+ dto = AppSchema()
424
+ dto.title = _('app.clash_verge_rev.title')
425
+ dto.description = _('app.clash_verge_rev.description')
426
+ dto.icon_url = self.__get_app_icon_url(_('app.clash_verge_rev.title'))
427
+ dto.guide_url = ''
428
+ dto.deeplink = f'clash://install-config/?url={self.user_panel_encoded_url}&name={self.profile_title}'
429
+
430
+ # availabe installatoin types
431
+ installation_types = []
432
+ if self.platform == Platform.all:
433
+ installation_types = [AppInstallType.setup, AppInstallType.appimage, AppInstallType.dmg]
434
+ else:
435
+ match self.platform:
436
+ case Platform.windows:
437
+ installation_types = [AppInstallType.setup]
438
+ case Platform.linux:
439
+ installation_types = [AppInstallType.appimage]
440
+ case Platform.mac:
441
+ installation_types = [AppInstallType.dmg]
442
+
443
+ install_dtos = []
444
+ for install_type in installation_types:
445
+ install_dto = AppInstall()
446
+ ins_url = ''
447
+ match install_type:
448
+ case AppInstallType.appimage:
449
+ ins_url = 'https://www.clashverge.dev/install.html#__tabbed_1_2'
450
+ case AppInstallType.setup:
451
+ ins_url = 'https://www.clashverge.dev/install.html#__tabbed_1_1'
452
+ case AppInstallType.dmg:
453
+ ins_url = 'https://www.clashverge.dev/install.html#__tabbed_1_3'
454
+
455
+ install_dto = self.__get_app_install_dto(install_type, ins_url)
456
+ install_dtos.append(install_dto)
457
+
458
+ dto.install = install_dtos
459
+ return dto
460
+
461
+ def __get_cmfa_app_dto(self):
462
+ dto = AppSchema()
463
+ dto.title = _('app.cmfa.title')
464
+ dto.description = _('app.cmfa.description')
465
+ dto.icon_url = self.__get_app_icon_url(_('app.cmfa.title'))
466
+ dto.guide_url = ''
467
+ dto.deeplink = f'clash://install-config/?url={self.user_panel_encoded_url}&name={self.profile_title}'
468
+
469
+ latest_url, version = get_latest_release_url(f'https://github.com/MetaCubeX/ClashMetaForAndroid')
470
+ ins_url = latest_url.split('releases/')[0] + f'releases/download/{version}/cmfa-{version}-meta-universal-release.apk'
471
+ def remove_v_from_filename(url):
472
+ parts = url.split('/')
473
+ filename = parts[-1]
474
+ new_filename = filename.replace('cmfa-v', 'cmfa-')
475
+ parts[-1] = new_filename
476
+ new_url = '/'.join(parts)
477
+ return new_url
478
+ ins_url = remove_v_from_filename(ins_url)
479
+ dto.install = [self.__get_app_install_dto(AppInstallType.apk, ins_url)]
480
+ return dto
481
+
412
482
  def __get_hiddify_next_app_dto(self):
413
483
  dto = AppSchema()
414
484
  dto.title = _('app.hiddify.next.title')
@@ -40,7 +40,11 @@ def init_app(app: APIFlask):
40
40
 
41
41
  @app.errorhandler(Exception)
42
42
  def internal_server_error(e):
43
- logger.exception(e)
43
+ if hasattr(e, 'code') and e.code == 404:
44
+ logger.error(f'{e} {request.url}')
45
+ else:
46
+ logger.exception(e)
47
+
44
48
  if isinstance(e, Exception):
45
49
  if hutils.flask.is_api_call(request.path):
46
50
  return jsonify({
@@ -133,8 +133,9 @@ class LoginView(FlaskView):
133
133
  @ route('/<secret_uuid>/manifest.webmanifest')
134
134
  def create_pwa_manifest(self):
135
135
  domain = request.host
136
- account=AdminUser.by_uuid(g.uuid)
137
- name = (domain if hutils.flask.is_admin_panel_call() else account.name)
136
+ admin_call=hutils.flask.is_admin_panel_call()
137
+ account=AdminUser.by_uuid(g.uuid) if admin_call else User.by_uuid(g.uuid)
138
+ name = (domain if admin_call else account.name)
138
139
  return jsonify({
139
140
  "name": f"Hiddify {name}",
140
141
  "short_name": f"{name}"[:12],
@@ -6,7 +6,7 @@ from typing import Tuple
6
6
  from flask import current_app, g
7
7
  from flask_babel import lazy_gettext as _
8
8
  from datetime import timedelta
9
-
9
+ import os
10
10
  from hiddifypanel.cache import cache
11
11
  from hiddifypanel.models import *
12
12
  from hiddifypanel.database import db
@@ -41,7 +41,7 @@ def add_short_link_imp(link: str, period_min: int = 5) -> Tuple[str, datetime]:
41
41
 
42
42
  pattern = r"([^/]+)\("
43
43
 
44
- with open(current_app.config['HIDDIFY_CONFIG_PATH'] + "/nginx/parts/short-link.conf", 'r') as f:
44
+ with open(os.environ['HIDDIFY_CONFIG_PATH'] + "/nginx/parts/short-link.conf", 'r') as f:
45
45
  for line in f:
46
46
  if link in line:
47
47
  return re.search(pattern, line).group(1), datetime.now() + timedelta(minutes=period_min)
@@ -146,14 +146,14 @@ def get_child(unique_id):
146
146
 
147
147
 
148
148
  def dump_db_to_dict():
149
- return {"childs": [u.to_dict() for u in Child.query.all()],
150
- "users": [u.to_dict() for u in User.query.all()],
151
- "domains": [u.to_dict() for u in Domain.query.all()],
152
- "proxies": [u.to_dict() for u in Proxy.query.all()],
149
+ return {"childs": [u.to_dict() for u in db.session.query(Child).all()],
150
+ "users": [u.to_dict() for u in db.session.query(User).all()],
151
+ "domains": [u.to_dict() for u in db.session.query(Domain).all()],
152
+ "proxies": [u.to_dict() for u in db.session.query(Proxy).all()],
153
153
  # "parent_domains": [] if not hconfig(ConfigEnum.license) else [u.to_dict() for u in ParentDomain.query.all()],
154
- 'admin_users': [d.to_dict() for d in AdminUser.query.all()],
155
- "hconfigs": [*[u.to_dict() for u in BoolConfig.query.all()],
156
- *[u.to_dict() for u in StrConfig.query.all()]]
154
+ 'admin_users': [d.to_dict() for d in db.session.query(AdminUser).all()],
155
+ "hconfigs": [*[u.to_dict() for u in db.session.query(BoolConfig).all()],
156
+ *[u.to_dict() for u in db.session.query(StrConfig).all()]]
157
157
  }
158
158
 
159
159
 
@@ -5,6 +5,8 @@ def logger_dynamic_formatter(record) -> str:
5
5
  fmt = '<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>'
6
6
  if record['extra']:
7
7
  fmt += ' | <level>{extra}</level>'
8
+ if record["exception"]:
9
+ fmt += "{exception}\n"
8
10
  return fmt + '\n'
9
11
 
10
12
  def init_app(app):
@@ -19,7 +21,7 @@ def init_logger(app, cli):
19
21
 
20
22
  logger.remove()
21
23
  logger.add(sys.stderr if cli else sys.stdout, format=logger_dynamic_formatter, level=app.config['STDOUT_LOG_LEVEL'],
22
- colorize=True, catch=True, enqueue=True, diagnose=False, backtrace=True)
24
+ colorize=True, catch=True, enqueue=True, diagnose=True, backtrace=True)
23
25
  logger.trace('Logger initiated :)')
24
26
 
25
27
  with app.app_context():