ddns 4.0.0b4__tar.gz → 4.0.0b6__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.

Potentially problematic release.


This version of ddns might be problematic. Click here for more details.

@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddns
3
- Version: 4.0.0b4
4
- Summary: automatically update DNS records to dynamic local IP [自动更新DNS记录指向本地IP]
3
+ Version: 4.0.0b6
4
+ Summary: automatically update DNS records to my IP [域名自动指向本机IP]
5
5
  Home-page: https://ddns.newfuture.cc
6
6
  Author: NewFuture
7
7
  Author-email: python@newfuture.cc
@@ -57,8 +57,12 @@ Dynamic: summary
57
57
 
58
58
  - 兼容和跨平台:
59
59
  - [Docker (@NN708)](https://hub.docker.com/r/newfuture/ddns) [![Docker Image Size](https://img.shields.io/docker/image-size/newfuture/ddns/latest?logo=docker&style=social)](https://hub.docker.com/r/newfuture/ddns)[![Docker Platforms](https://img.shields.io/badge/arch-amd64%20%7C%20arm64%20%7C%20arm%2Fv7%20%7C%20arm%2Fv6%20%7C%20ppc64le%20%7C%20s390x%20%7C%20386%20%7C%20mips64le-blue?style=social)](https://hub.docker.com/r/newfuture/ddns)
60
- - [PIP 安装 (兼容Python2)](https://pypi.org/project/ddns/) ![PyPI - Wheel](https://img.shields.io/pypi/wheel/ddns.svg?logo=pypi&style=social) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ddns.svg?style=social)
61
60
  - [二进制文件](https://github.com/NewFuture/DDNS/releases/latest) ![cross platform](https://img.shields.io/badge/system-windows_%7C%20linux_%7C%20mac-success.svg?style=social)
61
+
62
+ - 配置方式:
63
+ - [命令行参数](#详细配置)
64
+ - [JSON 配置文件](#详细配置)
65
+ - [环境变量配置](doc/env.md) 📖
62
66
 
63
67
  - 域名支持:
64
68
  - 多个域名支持
@@ -157,6 +161,8 @@ Dynamic: summary
157
161
  2. JSON 配置文件(值为 null 认为是有效值,会覆盖环境变量的设置,如果没有对应的 key 则会尝试使用环境变量)
158
162
  3. 环境变量 DDNS_ 前缀加上 key 全大写或者全小写,点转下划线(`${ddns_id}` 或 `${DDNS_ID}`,`${DDNS_LOG_LEVEL}`)
159
163
 
164
+ > 📖 **环境变量详细配置**: 查看 [环境变量配置文档](doc/env.md) 了解所有环境变量的详细用法和示例
165
+
160
166
  <details open>
161
167
  <summary markdown="span">config.json 配置文件</summary>
162
168
 
@@ -16,8 +16,12 @@
16
16
 
17
17
  - 兼容和跨平台:
18
18
  - [Docker (@NN708)](https://hub.docker.com/r/newfuture/ddns) [![Docker Image Size](https://img.shields.io/docker/image-size/newfuture/ddns/latest?logo=docker&style=social)](https://hub.docker.com/r/newfuture/ddns)[![Docker Platforms](https://img.shields.io/badge/arch-amd64%20%7C%20arm64%20%7C%20arm%2Fv7%20%7C%20arm%2Fv6%20%7C%20ppc64le%20%7C%20s390x%20%7C%20386%20%7C%20mips64le-blue?style=social)](https://hub.docker.com/r/newfuture/ddns)
19
- - [PIP 安装 (兼容Python2)](https://pypi.org/project/ddns/) ![PyPI - Wheel](https://img.shields.io/pypi/wheel/ddns.svg?logo=pypi&style=social) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ddns.svg?style=social)
20
19
  - [二进制文件](https://github.com/NewFuture/DDNS/releases/latest) ![cross platform](https://img.shields.io/badge/system-windows_%7C%20linux_%7C%20mac-success.svg?style=social)
20
+
21
+ - 配置方式:
22
+ - [命令行参数](#详细配置)
23
+ - [JSON 配置文件](#详细配置)
24
+ - [环境变量配置](doc/env.md) 📖
21
25
 
22
26
  - 域名支持:
23
27
  - 多个域名支持
@@ -116,6 +120,8 @@
116
120
  2. JSON 配置文件(值为 null 认为是有效值,会覆盖环境变量的设置,如果没有对应的 key 则会尝试使用环境变量)
117
121
  3. 环境变量 DDNS_ 前缀加上 key 全大写或者全小写,点转下划线(`${ddns_id}` 或 `${DDNS_ID}`,`${DDNS_LOG_LEVEL}`)
118
122
 
123
+ > 📖 **环境变量详细配置**: 查看 [环境变量配置文档](doc/env.md) 了解所有环境变量的详细用法和示例
124
+
119
125
  <details open>
120
126
  <summary markdown="span">config.json 配置文件</summary>
121
127
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddns
3
- Version: 4.0.0b4
4
- Summary: automatically update DNS records to dynamic local IP [自动更新DNS记录指向本地IP]
3
+ Version: 4.0.0b6
4
+ Summary: automatically update DNS records to my IP [域名自动指向本机IP]
5
5
  Home-page: https://ddns.newfuture.cc
6
6
  Author: NewFuture
7
7
  Author-email: python@newfuture.cc
@@ -57,8 +57,12 @@ Dynamic: summary
57
57
 
58
58
  - 兼容和跨平台:
59
59
  - [Docker (@NN708)](https://hub.docker.com/r/newfuture/ddns) [![Docker Image Size](https://img.shields.io/docker/image-size/newfuture/ddns/latest?logo=docker&style=social)](https://hub.docker.com/r/newfuture/ddns)[![Docker Platforms](https://img.shields.io/badge/arch-amd64%20%7C%20arm64%20%7C%20arm%2Fv7%20%7C%20arm%2Fv6%20%7C%20ppc64le%20%7C%20s390x%20%7C%20386%20%7C%20mips64le-blue?style=social)](https://hub.docker.com/r/newfuture/ddns)
60
- - [PIP 安装 (兼容Python2)](https://pypi.org/project/ddns/) ![PyPI - Wheel](https://img.shields.io/pypi/wheel/ddns.svg?logo=pypi&style=social) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ddns.svg?style=social)
61
60
  - [二进制文件](https://github.com/NewFuture/DDNS/releases/latest) ![cross platform](https://img.shields.io/badge/system-windows_%7C%20linux_%7C%20mac-success.svg?style=social)
61
+
62
+ - 配置方式:
63
+ - [命令行参数](#详细配置)
64
+ - [JSON 配置文件](#详细配置)
65
+ - [环境变量配置](doc/env.md) 📖
62
66
 
63
67
  - 域名支持:
64
68
  - 多个域名支持
@@ -157,6 +161,8 @@ Dynamic: summary
157
161
  2. JSON 配置文件(值为 null 认为是有效值,会覆盖环境变量的设置,如果没有对应的 key 则会尝试使用环境变量)
158
162
  3. 环境变量 DDNS_ 前缀加上 key 全大写或者全小写,点转下划线(`${ddns_id}` 或 `${DDNS_ID}`,`${DDNS_LOG_LEVEL}`)
159
163
 
164
+ > 📖 **环境变量详细配置**: 查看 [环境变量配置文档](doc/env.md) 了解所有环境变量的详细用法和示例
165
+
160
166
  <details open>
161
167
  <summary markdown="span">config.json 配置文件</summary>
162
168
 
@@ -6,12 +6,11 @@ DDNS
6
6
  @modified: rufengsuixing
7
7
  """
8
8
 
9
- # nuitka-project: --product-version=0.0.0
10
-
11
9
  from os import path, environ, name as os_name
10
+ from io import TextIOWrapper
11
+ from subprocess import check_output
12
12
  from tempfile import gettempdir
13
13
  from logging import basicConfig, info, warning, error, debug
14
- from subprocess import check_output
15
14
 
16
15
  import sys
17
16
 
@@ -19,8 +18,8 @@ from util import ip
19
18
  from util.cache import Cache
20
19
  from util.config import init_config, get_config
21
20
 
22
- __version__ = "v4.0.0-beta4@2025-06-10T17:58:37+00:00" # CI 时会被Tag替换
23
- __description__ = "automatically update DNS records to dynamic local IP [自动更新DNS记录指向本地IP]"
21
+ __version__ = "v4.0.0-beta6@2025-06-12T17:22:06+00:00" # CI 时会被Tag替换
22
+ __description__ = "automatically update DNS records to my IP [域名自动指向本机IP]"
24
23
  __doc__ = """
25
24
  ddns[%s]
26
25
  (i) homepage or docs [文档主页]: https://ddns.newfuture.cc/
@@ -28,12 +27,18 @@ ddns[%s]
28
27
  Copyright (c) New Future (MIT License)
29
28
  """ % (__version__)
30
29
 
31
- environ["DDNS_VERSION"] = "v4.0.0-beta4"
30
+ environ["DDNS_VERSION"] = "v4.0.0-beta6"
32
31
 
33
- if getattr(sys, 'frozen', False):
34
- # https://github.com/pyinstaller/pyinstaller/wiki/Recipe-OpenSSL-Certificate
35
- environ['SSL_CERT_FILE'] = path.join(
36
- getattr(sys, '_MEIPASS'), 'lib', 'cert.pem')
32
+
33
+ def is_false(value):
34
+ """
35
+ 判断值是否为 False
36
+ 字符串 'false', 或者 False, 或者 'none';
37
+ 0 不是 False
38
+ """
39
+ if isinstance(value, str):
40
+ return value.strip().lower() in ['false', 'none']
41
+ return value is False
37
42
 
38
43
 
39
44
  def get_ip(ip_type, index="default"):
@@ -45,7 +50,7 @@ def get_ip(ip_type, index="default"):
45
50
  value = None
46
51
  try:
47
52
  debug("get_ip(%s, %s)", ip_type, index)
48
- if index is False: # disabled
53
+ if is_false(index): # disabled
49
54
  return False
50
55
  elif isinstance(index, list): # 如果获取到的规则是列表,则依次判断列表中每一个规则,直到获取到IP
51
56
  for i in index:
@@ -120,12 +125,6 @@ def main():
120
125
  更新
121
126
  """
122
127
  init_config(__description__, __doc__, __version__)
123
- # Dynamicly import the dns module as configuration
124
- dns_provider = str(get_config('dns', 'dnspod').lower())
125
- dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider)
126
- dns.Config.ID = get_config('id')
127
- dns.Config.TOKEN = get_config('token')
128
- dns.Config.TTL = get_config('ttl')
129
128
 
130
129
  basicConfig(
131
130
  level=get_config('log.level'),
@@ -133,8 +132,15 @@ def main():
133
132
  datefmt='%m-%d %H:%M:%S',
134
133
  filename=get_config('log.file'),
135
134
  )
136
-
137
135
  info("DDNS[ %s ] run: %s %s", __version__, os_name, sys.platform)
136
+
137
+ # Dynamically import the dns module as configuration
138
+ dns_provider = str(get_config('dns', 'dnspod').lower())
139
+ dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider)
140
+ dns.Config.ID = get_config('id')
141
+ dns.Config.TOKEN = get_config('token')
142
+ dns.Config.TTL = get_config('ttl')
143
+
138
144
  if get_config("config"):
139
145
  info('loaded Config from: %s', path.abspath(get_config('config')))
140
146
 
@@ -162,10 +168,23 @@ def main():
162
168
 
163
169
 
164
170
  if __name__ == '__main__':
165
- encoding = sys.stdout.encoding
166
- if encoding is not None and encoding.lower() != 'utf-8':
171
+ encode = sys.stdout.encoding
172
+ if encode is not None and encode.lower() != 'utf-8' and hasattr(sys.stdout, 'buffer'):
167
173
  # 兼容windows 和部分ASCII编码的老旧系统
168
- from io import TextIOWrapper
169
174
  sys.stdout = TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
170
175
  sys.stderr = TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
171
176
  main()
177
+
178
+ # Nuitka Project Configuration
179
+ # nuitka-project: --mode=onefile
180
+ # nuitka-project: --output-filename=ddns
181
+ # nuitka-project: --product-name=DDNS
182
+ # nuitka-project: --product-version=0.0.0
183
+ # nuitka-project: --onefile-tempdir-spec="{TEMP}/{PRODUCT}_{VERSION}"
184
+ # nuitka-project: --no-deployment-flag=self-execution
185
+ # nuitka-project: --company-name="New Future"
186
+ # nuitka-project: --copyright=https://ddns.newfuture.cc
187
+ # nuitka-project: --assume-yes-for-downloads
188
+ # nuitka-project: --python-flag=no_site,no_asserts,no_docstrings,isolated,static_hashes
189
+ # nuitka-project: --nofollow-import-to=tkinter,unittest,pydoc,doctest,distutils,setuptools,lib2to3,test,idlelib,lzma
190
+ # nuitka-project: --noinclude-dlls=liblzma.*
@@ -4,6 +4,7 @@ from argparse import Action, ArgumentParser, Namespace, RawTextHelpFormatter
4
4
  from json import load as loadjson, dump as dumpjson
5
5
  from os import stat, environ, path
6
6
  from logging import error, getLevelName
7
+ from ast import literal_eval
7
8
 
8
9
  import sys
9
10
 
@@ -13,6 +14,11 @@ __config = {} # type: dict
13
14
  log_levels = ['CRITICAL', 'FATAL', 'ERROR',
14
15
  'WARN', 'WARNING', 'INFO', 'DEBUG', 'NOTSET']
15
16
 
17
+ # 支持数组的参数列表
18
+ ARRAY_PARAMS = ['index4', 'index6', 'ipv4', 'ipv6', 'proxy']
19
+ # 简单数组,支持’,’, ‘;’ 分隔的参数列表
20
+ SIMPLE_ARRAY_PARAMS = ['ipv4', 'ipv6', 'proxy']
21
+
16
22
 
17
23
  def str2bool(v):
18
24
  """
@@ -35,6 +41,32 @@ def log_level(value):
35
41
  return getLevelName(value.upper())
36
42
 
37
43
 
44
+ def parse_array_string(value, enable_simple_split):
45
+ """
46
+ 解析数组字符串
47
+ 仅当 trim 之后以 '[' 开头以 ']' 结尾时,才尝试使用 ast.literal_eval 解析
48
+ 默认返回原始字符串
49
+ """
50
+ if not isinstance(value, str):
51
+ return value
52
+
53
+ trimmed = value.strip()
54
+ if trimmed.startswith('[') and trimmed.endswith(']'):
55
+ try:
56
+ # 尝试使用 ast.literal_eval 解析数组
57
+ parsed_value = literal_eval(trimmed)
58
+ # 确保解析结果是列表或元组
59
+ if isinstance(parsed_value, (list, tuple)):
60
+ return list(parsed_value)
61
+ except (ValueError, SyntaxError) as e:
62
+ # 解析失败时返回原始字符串
63
+ error('Failed to parse array string: %s. Exception: %s', value, e)
64
+ elif enable_simple_split and ',' in trimmed:
65
+ # 尝试使用逗号或分号分隔符解析
66
+ return [item.strip() for item in trimmed.split(',') if item.strip()]
67
+ return value
68
+
69
+
38
70
  def init_config(description, doc, version):
39
71
  """
40
72
  配置
@@ -128,14 +160,16 @@ def get_config(key, default=None):
128
160
  return getattr(__cli_args, key)
129
161
  if key in __config:
130
162
  return __config.get(key)
163
+ # 检查环境变量
131
164
  env_name = 'DDNS_' + key.replace('.', '_') # type:str
132
- if env_name in environ: # 环境变量
133
- return environ.get(env_name)
134
- elif env_name.upper() in environ: # 大写环境变量
135
- return environ.get(env_name.upper())
136
- elif env_name.lower() in environ: # 小写环境变量
137
- return environ.get(env_name.lower())
138
- return default
165
+ variations = [env_name, env_name.upper(), env_name.lower()]
166
+ value = next((environ.get(v) for v in variations if v in environ), None)
167
+
168
+ # 如果找到环境变量值且参数支持数组,尝试解析为数组
169
+ if value is not None and key in ARRAY_PARAMS:
170
+ return parse_array_string(value, key in SIMPLE_ARRAY_PARAMS)
171
+
172
+ return value if value is not None else default
139
173
 
140
174
 
141
175
  class ExtendAction(Action):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes