|
26 | 26 | from feedgen.feed import FeedGenerator |
27 | 27 | from urllib.parse import urlparse |
28 | 28 | from requests_cache import CachedResponse |
29 | | -import logging |
30 | 29 |
|
31 | 30 | setattr(CachedResponse, "lazy", False) # https://github.com/jawah/niquests/issues/241 |
32 | 31 |
|
33 | | -# 設置日誌 |
34 | | -logging.basicConfig(level=logging.INFO) |
35 | | -logger = logging.getLogger(__name__) |
36 | | - |
37 | 32 | # ------------------------------ |
38 | 33 | # 初始設定:檢查環境並顯示提示 |
39 | 34 | def initial_setup(): |
@@ -61,8 +56,7 @@ class CachedSession(requests_cache.session.CacheMixin, niquests.Session): |
61 | 56 | # 建立網路請求的 Session,包含緩存和 QUIC 支援 |
62 | 57 | session = CachedSession( |
63 | 58 | # allowable_methods=('GET', 'HEAD'), # 支援的 HTTP 方法 |
64 | | - # resolver="doh://mozilla.cloudflare-dns.com/dns-query", # 使用 DoH 解析 DNS |
65 | | - resolver="doh://8.8.8.8/dns-query", |
| 59 | + resolver="doh://mozilla.cloudflare-dns.com/dns-query", # 使用 DoH 解析 DNS |
66 | 60 | pool_connections=poolConn, # 連線池設定 |
67 | 61 | pool_maxsize=poolSize, |
68 | 62 | backend='redis', # 緩存後端使用 Redis |
@@ -177,91 +171,63 @@ def modify_image_url(imageUrl, new_quality): |
177 | 171 | new_url = new_url.replace('n=-1&w=720', 'n=-1&we&w=720') # 修正特定參數 |
178 | 172 | return new_url |
179 | 173 |
|
180 | | -async def optimize_image_quality(image_url, max_size_bytes=50*1000, min_quality=1, max_quality=99, extra_quality_reduction=10): |
181 | | - """ |
182 | | - 優化圖片品質,返還品質最低(quality 最小)但大小不超過 max_size_bytes 嘅圖片 URL。 |
183 | | - 如果 x-upstream-response-length 或 quality=max_quality 嘅圖片 ≤ max_size_bytes,會將 quality 再調低 extra_quality_reduction。 |
184 | | -
|
185 | | - :param image_url: 原始圖片 URL |
186 | | - :param max_size_bytes: 目標圖片大小(預設 50KB = 50,000 字節) |
187 | | - :param min_quality: 最小品質(預設 1) |
188 | | - :param max_quality: 最大品質(預設 99) |
189 | | - :param extra_quality_reduction: 額外減低嘅 quality 值(預設 10) |
190 | | - :return: 優化後嘅圖片 URL |
191 | | - """ |
192 | | - # 獲取 quality=max_quality 嘅圖片 URL(即 q=99) |
193 | | - max_quality_url = modify_image_url(image_url, max_quality) |
| 174 | +async def optimize_image_quality(imgUrl): |
| 175 | + # 優化圖片品質,確保檔案大小適中 |
| 176 | + q = 99 # 初始品質 |
| 177 | + latest_imgUrl = modify_image_url(imgUrl, 1) |
| 178 | + latestAvailableQ = None |
| 179 | + content_length_q99 = None |
194 | 180 |
|
195 | | - try: |
196 | | - # 發送 HEAD 請求獲取圖片資訊 |
197 | | - response = await get_response(max_quality_url, method='HEAD', session=session) |
198 | | - |
199 | | - if response.ok: |
200 | | - # 獲取 x-upstream-response-length(原始圖片大小) |
201 | | - upstream_response_length = int(response.headers.get('x-upstream-response-length', 0)) |
202 | | - |
203 | | - # 獲取 q=99 嘅圖片大小 |
204 | | - max_quality_size = int(response.headers.get('Content-Length', 0)) |
205 | | - else: |
206 | | - upstream_response_length = None |
207 | | - max_quality_size = None |
208 | | - logger.warning(f"獲取 quality=max_quality 圖片資訊失敗,HTTP 狀態碼: {response.status_code}") |
209 | | - except Exception as e: |
210 | | - upstream_response_length = None |
211 | | - max_quality_size = None |
212 | | - logger.error(f"獲取 quality=max_quality 圖片資訊出錯: {e}") |
213 | | - |
214 | | - low, high = min_quality, max_quality |
215 | | - best_image_url = None |
216 | | - best_quality = max_quality + 1 # 初始值設為 max_quality + 1,確保可以更新 |
217 | | - |
218 | | - # 二分搜索搵 quality 最小嘅圖片 |
219 | | - while low <= high: |
220 | | - mid_quality = (low + high) // 2 |
221 | | - current_image_url = modify_image_url(image_url, mid_quality) |
222 | | - |
| 181 | + while True: |
| 182 | + imgUrlWithQ = modify_image_url(imgUrl, q) |
223 | 183 | try: |
224 | | - response = await get_response(current_image_url, method='HEAD', session=session) |
| 184 | + response = await get_response(imgUrlWithQ, method='HEAD', session=session) |
225 | 185 | if response.status_code >= 400 and response.status_code < 600: |
226 | | - logger.warning(f"HTTP 錯誤: {response.status_code}, URL: {current_image_url}") |
227 | | - low = mid_quality + 1 |
228 | | - continue |
229 | | - |
230 | | - if response.ok: |
231 | | - current_size = int(response.headers.get('Content-Length', 0)) |
232 | | - logger.info(f"圖片大小: {current_size} bytes, quality: {mid_quality}, URL: {current_image_url}") |
233 | | - |
234 | | - # 檢查圖片大小同原始圖片 |
235 | | - if current_size > max_size_bytes or (upstream_response_length is not None and current_size > upstream_response_length): |
236 | | - low = mid_quality + 1 |
| 186 | + if q > 1: |
| 187 | + q = 1 |
| 188 | + print(f"圖片品質設為 1,因 HTTP 狀態: {response.status_code}, URL: {imgUrl}") |
237 | 189 | else: |
238 | | - if mid_quality < best_quality: |
239 | | - best_image_url = current_image_url |
240 | | - best_quality = mid_quality |
241 | | - high = mid_quality - 1 |
242 | | - else: |
243 | | - logger.warning(f"響應不成功: {response.status_code}, URL: {current_image_url}") |
244 | | - low = mid_quality + 1 |
245 | | - |
| 190 | + print(f"無法獲取圖片,退出迴圈, URL: {imgUrl}") |
| 191 | + break |
| 192 | + |
| 193 | + elif response.ok: |
| 194 | + latestAvailableQ = imgUrlWithQ |
| 195 | + content_length = int(response.headers.get('Content-Length', 0)) |
| 196 | + upstream_response_length = int(response.headers.get('x-upstream-response-length', 0)) |
| 197 | + print(f"圖片大小: {content_length} bytes, Upstream: {upstream_response_length}, q: {q}, URL: {imgUrl}") |
| 198 | + |
| 199 | + if q == 99: |
| 200 | + content_length_q99 = content_length |
| 201 | + |
| 202 | + if q == 1: |
| 203 | + print(f"品質已降至 1,退出迴圈, URL: {imgUrl}") |
| 204 | + break |
| 205 | + |
| 206 | + if content_length > 1000 * 50 or content_length > upstream_response_length: |
| 207 | + if q == 99: |
| 208 | + q = 95 |
| 209 | + if q <= 95: |
| 210 | + q = max(1, q - 5) |
| 211 | + elif content_length <= 1000 * 50: |
| 212 | + print(f"圖片小於 100KB,品質適中, URL: {imgUrl}, q: {q}") |
| 213 | + latest_imgUrl = latestAvailableQ if latestAvailableQ else imgUrlWithQ |
| 214 | + break |
| 215 | + |
246 | 216 | except Exception as e: |
247 | | - logger.error(f"獲取圖片大小失敗, URL: {current_image_url}, 錯誤: {e}") |
248 | | - low = mid_quality + 1 |
249 | | - |
250 | | - # 如果搵唔到符合條件嘅 URL,返 min_quality 嘅 URL |
251 | | - if best_image_url is None: |
252 | | - best_image_url = modify_image_url(image_url, min_quality) |
253 | | - logger.warning(f"搵唔到大小 ≤ {max_size_bytes} bytes 嘅圖片,返 min_quality={min_quality} 嘅 URL: {best_image_url}") |
254 | | - return best_image_url |
255 | | - |
256 | | - # 檢查 x-upstream-response-length 或 quality=max_quality |
257 | | - if (upstream_response_length is not None and upstream_response_length <= max_size_bytes) or \ |
258 | | - (max_quality_size is not None and max_quality_size <= max_size_bytes): |
259 | | - # 如果 x-upstream-response-length 或 quality=max_quality ≤ max_size_bytes,調低 quality |
260 | | - adjusted_quality = max(min_quality, best_quality - extra_quality_reduction) |
261 | | - best_image_url = modify_image_url(image_url, adjusted_quality) |
262 | | - logger.info(f"x-upstream-response-length 或 quality=max_quality ≤ {max_size_bytes} bytes,調低 quality 至 {adjusted_quality}, URL: {best_image_url}") |
263 | | - |
264 | | - return best_image_url |
| 217 | + print(f"獲取圖片大小失敗, URL: {imgUrl}, 錯誤: {e}") |
| 218 | + q = 1 |
| 219 | + latest_imgUrl = latestAvailableQ if latestAvailableQ else imgUrlWithQ |
| 220 | + break |
| 221 | + |
| 222 | + if (upstream_response_length <= 1000 * 50 or (content_length_q99 is not None and content_length_q99 <= 1000 * 50)): |
| 223 | + if q == 99: |
| 224 | + q = 90 |
| 225 | + elif q <= 95: |
| 226 | + q = max(1, q - 10) |
| 227 | + latest_imgUrl = modify_image_url(imgUrl, q) |
| 228 | + print(f"圖片小於 100KB,調整品質至 q={q}, URL: {latest_imgUrl}") |
| 229 | + |
| 230 | + return latest_imgUrl |
265 | 231 |
|
266 | 232 | # ------------------------------ |
267 | 233 | # HTTP 請求函數:支援緩存與錯誤重試 |
|
0 commit comments