返回提交历史
Modified
g4f/Provider/needs_auth/Video.py
+1
-4
Modified
g4f/image/copy_images.py
+16
-7
Modified
g4f/providers/response.py
+11
-3
XFEstudio/gpt4free
Improve update script
ffb1914c
代码差异
3 个文件
+28
-14
@@ -1,8 +1,6 @@
1
1
from __future__ import annotations
2
2
3
import time
4
3
import asyncio
5
import random
6
4
from aiohttp import ClientSession, ClientTimeout
7
5
8
6
from urllib.parse import quote, quote_plus
@@ -35,7 +33,6 @@ class RequestConfig:
35
33
unique_list = list(set(cls.urls[prompt]))[:10]
36
34
return VideoResponse(unique_list, prompt, {
37
35
"headers": {"authorization": cls.headers.get("authorization")} if cls.headers.get("authorization") else {},
38
"preview": [url.replace("md.mp4", "thumb.webp") for url in unique_list]
39
36
})
40
37
async with ClientSession() as session:
41
38
found_urls = []
@@ -135,7 +132,7 @@ class Video(AsyncGeneratorProvider, ProviderModelMixin):
135
132
page.add_handler(nodriver.cdp.network.RequestWillBeSent, on_request)
136
133
if model == "search":
137
134
for _ in range(5):
138
await page.scroll_down(50)
135
await page.scroll_down(5)
139
136
await asyncio.sleep(1)
140
137
response = await RequestConfig.get_response(prompt)
141
138
if response:
@@ -39,7 +39,7 @@ def get_media_extension(media: str) -> str:
39
39
if not extension or len(extension) > 4:
40
40
return ""
41
41
if extension[1:] not in EXTENSIONS_MAP:
42
raise ValueError(f"Unsupported media extension: {extension} in: {media}")
42
raise ""
43
43
return extension
44
44
45
45
def ensure_media_dir():
@@ -55,11 +55,10 @@ def get_source_url(image: str, default: str = None) -> str:
55
55
return decoded_url
56
56
return default
57
57
58
def get_target_path(response, filename: str) -> str:
58
def update_filename(response, filename: str) -> str:
59
59
date = response.headers.get("last-modified", response.headers.get("date"))
60
60
timestamp = datetime.strptime(date, '%a, %d %b %Y %H:%M:%S %Z').timestamp()
61
filename = str(int(timestamp)) + "_" + filename.split("_", maxsplit=1)[-1]
62
return os.path.join(get_media_dir(), filename)
61
return str(int(timestamp)) + "_" + filename.split("_", maxsplit=1)[-1]
63
62
64
63
async def save_response_media(response, prompt: str, tags: list[str]) -> AsyncIterator:
65
64
"""Save media from response to local file and return URL"""
@@ -71,7 +70,8 @@ async def save_response_media(response, prompt: str, tags: list[str]) -> AsyncIt
71
70
raise ValueError(f"Unsupported media type: {content_type}")
72
71
73
72
filename = get_filename(tags, prompt, f".{extension}", prompt)
74
target_path = get_target_path(response, filename)
73
filename = update_filename(response, filename)
74
target_path = os.path.join(get_media_dir(), filename)
75
75
ensure_media_dir()
76
76
with open(target_path, 'wb') as f:
77
77
if isinstance(response, bytes):
@@ -117,6 +117,7 @@ async def copy_media(
117
117
tags: list[str] = None,
118
118
add_url: Union[bool, str] = True,
119
119
target: str = None,
120
thumbnail: bool = False,
120
121
ssl: bool = None,
121
122
timeout: Optional[int] = None
122
123
) -> list[str]:
@@ -127,6 +128,11 @@ async def copy_media(
127
128
if add_url:
128
129
add_url = not cookies
129
130
ensure_media_dir()
131
media_dir = get_media_dir()
132
if thumbnail:
133
media_dir = os.path.join(media_dir, "thumbnails")
134
if not os.path.exists(media_dir):
135
os.makedirs(media_dir, exist_ok=True)
130
136
131
137
async with ClientSession(
132
138
connector=get_connector(proxy=proxy),
@@ -149,7 +155,7 @@ async def copy_media(
149
155
filename = secure_filename(path[len("/media/"):])
150
156
else:
151
157
filename = get_filename(tags, alt, media_extension, image)
152
target_path = os.path.join(get_media_dir(), filename)
158
target_path = os.path.join(media_dir, filename)
153
159
try:
154
160
# Handle different image types
155
161
if image.startswith("data:"):
@@ -167,7 +173,8 @@ async def copy_media(
167
173
async with session.get(image, ssl=request_ssl, headers=request_headers) as response:
168
174
response.raise_for_status()
169
175
if target is None:
170
target_path = get_target_path(response, filename)
176
filename = update_filename(response, filename)
177
target_path = os.path.join(media_dir, filename)
171
178
media_type = response.headers.get("content-type", "application/octet-stream")
172
179
if media_type not in ("application/octet-stream", "binary/octet-stream"):
173
180
if media_type not in MEDIA_TYPE_MAP:
@@ -190,6 +197,8 @@ async def copy_media(
190
197
target_path = f"{target_path}{media_extension}"
191
198
except ValueError:
192
199
pass
200
if thumbnail:
201
return "/thumbnail/" + os.path.basename(target_path)
193
202
# Build URL relative to media directory
194
203
return f"/media/{os.path.basename(target_path)}" + ('?' + (add_url if isinstance(add_url, str) else '' + 'url=' + quote(image)) if add_url and not image.startswith('data:') else '')
195
204
@@ -339,9 +339,9 @@ class MediaResponse(ResponseType):
339
339
self.alt = alt
340
340
self.options = options
341
341
342
def get(self, key: str) -> any:
342
def get(self, key: str, default: any = None) -> any:
343
343
"""Get an option value by key."""
344
return self.options.get(key)
344
return self.options.get(key, default)
345
345
346
346
def get_list(self) -> List[str]:
347
347
"""Return images as a list."""
@@ -355,7 +355,15 @@ class ImageResponse(MediaResponse):
355
355
class VideoResponse(MediaResponse):
356
356
def __str__(self) -> str:
357
357
"""Return videos as html elements."""
358
return "\n".join([f'<video controls src="{video}"></video>' for video in self.get_list()])
358
if self.get("preview"):
359
result = []
360
for idx, video in enumerate(self.get_list()):
361
image = self.get("preview")
362
if isinstance(image, list) and len(image) > idx:
363
image = image[idx]
364
result.append(f'<video controls src="{quote_url(video)}" poster="{quote_url(image)}"></video>')
365
return "\n".join(result)
366
return "\n".join([f'<video controls src="{quote_url(video)}"></video>' for video in self.get_list()])
359
367
360
368
class ImagePreview(ImageResponse):
361
369
def __str__(self) -> str: