ddns 3.1.6__py2.py3-none-any.whl → 4.0.0__py2.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.

Potentially problematic release.


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

ddns/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ # -*- coding:utf-8 -*-
2
+ """
3
+ ddns Package
4
+ """
5
+
6
+ __description__ = "automatically update DNS records to my IP [域名自动指向本机IP]"
7
+
8
+ # 编译时,版本会被替换
9
+ __version__ = "4.0.0"
10
+
11
+ # 时间也会被替换掉
12
+ build_date = "2025-06-20T15:39:20Z"
13
+
14
+ __doc__ = """
15
+ ddns [v{}@{}]
16
+ (i) homepage or docs [文档主页]: https://ddns.newfuture.cc/
17
+ (?) issues or bugs [问题和反馈]: https://github.com/NewFuture/DDNS/issues
18
+ Copyright (c) New Future (MIT License)
19
+ """.format(__version__, build_date)
ddns/__main__.py ADDED
@@ -0,0 +1,180 @@
1
+ # -*- coding:utf-8 -*-
2
+ """
3
+ DDNS
4
+ @author: New Future
5
+ @modified: rufengsuixing
6
+ """
7
+
8
+ from os import path, environ, name as os_name
9
+ from io import TextIOWrapper
10
+ from subprocess import check_output
11
+ from tempfile import gettempdir
12
+ from logging import basicConfig, info, warning, error, debug, DEBUG, NOTSET
13
+
14
+ import sys
15
+
16
+ from .__init__ import __version__, __description__, __doc__, build_date
17
+ from .util import ip
18
+ from .util.cache import Cache
19
+ from .util.config import init_config, get_config
20
+
21
+ environ["DDNS_VERSION"] = __version__
22
+
23
+
24
+ def is_false(value):
25
+ """
26
+ 判断值是否为 False
27
+ 字符串 'false', 或者 False, 或者 'none';
28
+ 0 不是 False
29
+ """
30
+ if isinstance(value, str):
31
+ return value.strip().lower() in ['false', 'none']
32
+ return value is False
33
+
34
+
35
+ def get_ip(ip_type, index="default"):
36
+ """
37
+ get IP address
38
+ """
39
+ # CN: 捕获异常
40
+ # EN: Catch exceptions
41
+ value = None
42
+ try:
43
+ debug("get_ip(%s, %s)", ip_type, index)
44
+ if is_false(index): # disabled
45
+ return False
46
+ elif isinstance(index, list): # 如果获取到的规则是列表,则依次判断列表中每一个规则,直到获取到IP
47
+ for i in index:
48
+ value = get_ip(ip_type, i)
49
+ if value:
50
+ break
51
+ elif str(index).isdigit(): # 数字 local eth
52
+ value = getattr(ip, "local_v" + ip_type)(index)
53
+ elif index.startswith('cmd:'): # cmd
54
+ value = str(check_output(index[4:]).strip().decode('utf-8'))
55
+ elif index.startswith('shell:'): # shell
56
+ value = str(check_output(
57
+ index[6:], shell=True).strip().decode('utf-8'))
58
+ elif index.startswith('url:'): # 自定义 url
59
+ value = getattr(ip, "public_v" + ip_type)(index[4:])
60
+ elif index.startswith('regex:'): # 正则 regex
61
+ value = getattr(ip, "regex_v" + ip_type)(index[6:])
62
+ else:
63
+ value = getattr(ip, index + "_v" + ip_type)()
64
+ except Exception as e:
65
+ error("Failed to get %s address: %s", ip_type, e)
66
+ return value
67
+
68
+
69
+ def change_dns_record(dns, proxy_list, **kw):
70
+ for proxy in proxy_list:
71
+ if not proxy or (proxy.upper() in ['DIRECT', 'NONE']):
72
+ dns.Config.PROXY = None
73
+ else:
74
+ dns.Config.PROXY = proxy
75
+ record_type, domain = kw['record_type'], kw['domain']
76
+ info("%s(%s) ==> %s [via %s]", domain, record_type, kw['ip'], proxy)
77
+ try:
78
+ return dns.update_record(domain, kw['ip'], record_type=record_type)
79
+ except Exception as e:
80
+ error("Failed to update %s record for %s: %s", record_type, domain, e)
81
+ return False
82
+
83
+
84
+ def update_ip(ip_type, cache, dns, proxy_list):
85
+ """
86
+ 更新IP
87
+ """
88
+ ipname = 'ipv' + ip_type
89
+ domains = get_config(ipname)
90
+ if not domains:
91
+ return None
92
+ if not isinstance(domains, list):
93
+ domains = domains.strip('; ').replace(',', ';').replace(' ', ';').split(';')
94
+
95
+ index_rule = get_config('index' + ip_type, "default")
96
+ address = get_ip(ip_type, index_rule)
97
+ if not address:
98
+ error('Fail to get %s address!', ipname)
99
+ return False
100
+
101
+ if cache and (address == cache.get(ipname)):
102
+ info('%s address not changed, using cache.', ipname)
103
+ return True
104
+
105
+ record_type = 'A' if ip_type == '4' else 'AAAA'
106
+ update_success = False
107
+ for domain in domains:
108
+ domain = domain.lower()
109
+ if change_dns_record(dns, proxy_list, domain=domain, ip=address, record_type=record_type):
110
+ update_success = True
111
+
112
+ if isinstance(cache, dict):
113
+ cache[ipname] = update_success and address
114
+
115
+ return update_success
116
+
117
+
118
+ def main():
119
+ """
120
+ 更新
121
+ """
122
+ encode = sys.stdout.encoding
123
+ if encode is not None and encode.lower() != 'utf-8' and hasattr(sys.stdout, 'buffer'):
124
+ # 兼容windows 和部分ASCII编码的老旧系统
125
+ sys.stdout = TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
126
+ sys.stderr = TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
127
+ init_config(__description__, __doc__, __version__, build_date)
128
+
129
+ log_level = get_config('log.level')
130
+ log_format = get_config('log.format', '%(asctime)s %(levelname)s [%(module)s]: %(message)s')
131
+ # Override log format in debug mode to include filename and line number for detailed debugging
132
+ if (log_level == DEBUG or log_level == NOTSET) and not log_format:
133
+ log_format = '%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]: %(message)s'
134
+ basicConfig(
135
+ level=log_level,
136
+ format=log_format,
137
+ datefmt=get_config('log.datefmt', '%Y-%m-%dT%H:%M:%S'),
138
+ filename=get_config('log.file'),
139
+ )
140
+
141
+ info("DDNS[ %s ] run: %s %s", __version__, os_name, sys.platform)
142
+
143
+ # Dynamically import the dns module as configuration
144
+ dns_provider = str(get_config('dns', 'dnspod').lower())
145
+ # dns_module = __import__(
146
+ # '.dns', fromlist=[dns_provider], package=__package__)
147
+ dns = getattr(__import__('ddns.provider', fromlist=[dns_provider]), dns_provider)
148
+ # dns = getattr(dns_module, dns_provider)
149
+ dns.Config.ID = get_config('id')
150
+ dns.Config.TOKEN = get_config('token')
151
+ dns.Config.TTL = get_config('ttl')
152
+
153
+ if get_config("config"):
154
+ info('loaded Config from: %s', path.abspath(get_config('config')))
155
+
156
+ proxy = get_config('proxy') or 'DIRECT'
157
+ proxy_list = proxy if isinstance(
158
+ proxy, list) else proxy.strip(';').replace(',', ';').split(';')
159
+
160
+ cache_config = get_config('cache', True)
161
+ if cache_config is False:
162
+ cache = cache_config
163
+ elif cache_config is True:
164
+ cache = Cache(path.join(gettempdir(), 'ddns.cache'))
165
+ else:
166
+ cache = Cache(cache_config)
167
+
168
+ if cache is False:
169
+ info('Cache is disabled!')
170
+ elif not get_config('config_modified_time') or get_config('config_modified_time') >= cache.time:
171
+ warning('Cache file is outdated.')
172
+ cache.clear()
173
+ else:
174
+ debug('Cache is empty.')
175
+ update_ip('4', cache, dns, proxy_list)
176
+ update_ip('6', cache, dns, proxy_list)
177
+
178
+
179
+ if __name__ == '__main__':
180
+ main()
@@ -14,14 +14,12 @@ from json import loads as jsondecode
14
14
  from logging import debug, info, warning
15
15
  from datetime import datetime
16
16
 
17
- try:
18
- # python 2
19
- from httplib import HTTPSConnection
20
- from urllib import urlencode, quote_plus, quote
21
- except ImportError:
22
- # python 3
17
+ try: # python 3
23
18
  from http.client import HTTPSConnection
24
19
  from urllib.parse import urlencode, quote_plus, quote
20
+ except ImportError: # python 2
21
+ from httplib import HTTPSConnection
22
+ from urllib import urlencode, quote_plus, quote
25
23
 
26
24
  __author__ = 'New Future'
27
25
  # __all__ = ["request", "ID", "TOKEN", "PROXY"]
@@ -10,15 +10,13 @@ from json import loads as jsondecode
10
10
  from logging import debug, info, warning
11
11
  from time import time
12
12
 
13
- try:
14
- # python 2
13
+ try: # python 3
14
+ from http.client import HTTPSConnection, HTTPConnection
15
+ from urllib.parse import urlencode, urlparse, parse_qsl
16
+ except ImportError: # python 2
15
17
  from httplib import HTTPSConnection, HTTPConnection
16
18
  from urlparse import urlparse, parse_qsl
17
19
  from urllib import urlencode
18
- except ImportError:
19
- # python 3
20
- from http.client import HTTPSConnection, HTTPConnection
21
- from urllib.parse import urlencode, urlparse, parse_qsl
22
20
 
23
21
  __author__ = '老周部落'
24
22
 
@@ -9,14 +9,12 @@ https://api.cloudflare.com/#dns-records-for-a-zone-properties
9
9
  from json import loads as jsondecode, dumps as jsonencode
10
10
  from logging import debug, info, warning
11
11
 
12
- try:
13
- # python 2
14
- from httplib import HTTPSConnection
15
- from urllib import urlencode
16
- except ImportError:
17
- # python 3
12
+ try: # python 3
18
13
  from http.client import HTTPSConnection
19
14
  from urllib.parse import urlencode
15
+ except ImportError: # python 2
16
+ from httplib import HTTPSConnection
17
+ from urllib import urlencode
20
18
 
21
19
  __author__ = 'TongYifan'
22
20
 
@@ -13,15 +13,12 @@ from logging import debug, info, warning
13
13
  from time import mktime
14
14
  from datetime import datetime
15
15
 
16
- try:
17
- # python 2
18
- from httplib import HTTPSConnection
19
- from urllib import urlencode
20
- except ImportError:
21
- # python 3
16
+ try: # python 3
22
17
  from http.client import HTTPSConnection
23
18
  from urllib.parse import urlencode
24
-
19
+ except ImportError: # python 2
20
+ from httplib import HTTPSConnection
21
+ from urllib import urlencode
25
22
 
26
23
  __author__ = 'Bigjin'
27
24
  # __all__ = ["request", "ID", "TOKEN", "PROXY"]
@@ -9,14 +9,13 @@ http://www.dnspod.cn/docs/domains.html
9
9
  from json import loads as jsondecode
10
10
  from logging import debug, info, warning
11
11
  from os import environ
12
- try:
13
- # python 2
14
- from httplib import HTTPSConnection
15
- from urllib import urlencode
16
- except ImportError:
17
- # python 3
12
+
13
+ try: # python 3
18
14
  from http.client import HTTPSConnection
19
15
  from urllib.parse import urlencode
16
+ except ImportError: # python 2
17
+ from httplib import HTTPSConnection
18
+ from urllib import urlencode
20
19
 
21
20
  __author__ = 'New Future'
22
21
 
@@ -107,10 +106,11 @@ def get_domain_id(domain):
107
106
  return get_domain_id.domain_list[domain]
108
107
  else:
109
108
  try:
110
- info = request('Domain.Info', domain=domain)
111
- except Exception:
109
+ d_info = request('Domain.Info', domain=domain)
110
+ except Exception as e:
111
+ info("get_domain_id(%s) error: %s", domain, e)
112
112
  return
113
- did = info.get("domain", {}).get("id")
113
+ did = d_info.get("domain", {}).get("id")
114
114
  if did:
115
115
  get_domain_id.domain_list[domain] = did
116
116
  return did
@@ -6,7 +6,7 @@ http://www.dnspod.com/docs/domains.html
6
6
  @author: New Future
7
7
  """
8
8
 
9
- from dns.dnspod import * # noqa: F403
9
+ from .dnspod import * # noqa: F403
10
10
 
11
11
  API.SITE = "api.dnspod.com" # noqa: F405
12
12
  API.DEFAULT = "default" # noqa: F405
@@ -8,14 +8,12 @@ https://dns.he.net/docs.html
8
8
 
9
9
  from logging import debug, info, warning
10
10
 
11
- try:
12
- # python 2
13
- from httplib import HTTPSConnection
14
- from urllib import urlencode
15
- except ImportError:
16
- # python 3
11
+ try: # python 3
17
12
  from http.client import HTTPSConnection
18
13
  from urllib.parse import urlencode
14
+ except ImportError: # python 2
15
+ from httplib import HTTPSConnection
16
+ from urllib import urlencode
19
17
 
20
18
  __author__ = 'NN708'
21
19
 
@@ -14,14 +14,13 @@ from json import loads as jsondecode, dumps as jsonencode
14
14
  from logging import debug, info, warning
15
15
  from datetime import datetime
16
16
 
17
- try:
18
- # python 2
19
- from httplib import HTTPSConnection
20
- from urllib import urlencode
21
- except ImportError:
22
- # python 3
17
+ try: # python 3
23
18
  from http.client import HTTPSConnection
24
19
  from urllib.parse import urlencode
20
+ except ImportError: # python 2
21
+ from httplib import HTTPSConnection
22
+ from urllib import urlencode
23
+
25
24
 
26
25
  __author__ = 'New Future'
27
26
  BasicDateFormat = "%Y%m%dT%H%M%SZ"
@@ -11,12 +11,10 @@ from time import time
11
11
 
12
12
  from logging import info, debug, warning
13
13
 
14
- try:
15
- # Python 2
16
- from collections import MutableMapping
17
- except ImportError:
18
- # python3
14
+ try: # python 3
19
15
  from collections.abc import MutableMapping
16
+ except ImportError: # python 2
17
+ from collections import MutableMapping
20
18
 
21
19
 
22
20
  class Cache(MutableMapping):