qdown 1.0.3__py3-none-any.whl → 1.0.4__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.
- qdown/__init__.py +3 -3
- qdown/qdown.py +107 -0
- {qdown-1.0.3.dist-info → qdown-1.0.4.dist-info}/METADATA +3 -1
- qdown-1.0.4.dist-info/RECORD +10 -0
- qdown-1.0.3.dist-info/RECORD +0 -10
- {qdown-1.0.3.dist-info → qdown-1.0.4.dist-info}/WHEEL +0 -0
- {qdown-1.0.3.dist-info → qdown-1.0.4.dist-info}/entry_points.txt +0 -0
- {qdown-1.0.3.dist-info → qdown-1.0.4.dist-info}/top_level.txt +0 -0
qdown/__init__.py
CHANGED
@@ -75,9 +75,9 @@ def download(download_url, output_path=None, output_dir=None, server_url="https:
|
|
75
75
|
# QDownクライアントの初期化
|
76
76
|
client = QDown(server_url=server_url, quiet=quiet)
|
77
77
|
|
78
|
-
#
|
79
|
-
return
|
78
|
+
# 同期版メソッドを呼び出す
|
79
|
+
return client.download_by_file_id_sync(
|
80
80
|
file_id=file_id,
|
81
81
|
output=output_path,
|
82
82
|
output_dir=output_dir
|
83
|
-
)
|
83
|
+
)
|
qdown/qdown.py
CHANGED
@@ -147,6 +147,113 @@ class QDown:
|
|
147
147
|
print(f"エラー: {e}", file=sys.stderr)
|
148
148
|
return None
|
149
149
|
|
150
|
+
def download_by_file_id_sync(self, file_id, output=None, output_dir=None):
|
151
|
+
"""
|
152
|
+
ファイルIDを指定してファイルをダウンロード(同期版)
|
153
|
+
|
154
|
+
Args:
|
155
|
+
file_id (str): ダウンロードするファイルのID (qd_id)
|
156
|
+
output (str, optional): 出力ファイル名
|
157
|
+
output_dir (str, optional): 出力ディレクトリ
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
str: ダウンロードしたファイルのパス
|
161
|
+
"""
|
162
|
+
url = f"{self.server_url}/download/{file_id}"
|
163
|
+
|
164
|
+
# 出力ディレクトリの設定
|
165
|
+
if output_dir:
|
166
|
+
os.makedirs(output_dir, exist_ok=True)
|
167
|
+
else:
|
168
|
+
output_dir = "."
|
169
|
+
|
170
|
+
with httpx.Client(timeout=self.timeout) as client:
|
171
|
+
# まず、ヘッド要求を送信してファイル情報を取得
|
172
|
+
try:
|
173
|
+
head_response = client.head(url)
|
174
|
+
|
175
|
+
if head_response.status_code == 404:
|
176
|
+
print(f"エラー: ID '{file_id}' のファイルが見つかりませんでした", file=sys.stderr)
|
177
|
+
return None
|
178
|
+
|
179
|
+
if head_response.status_code != 200:
|
180
|
+
print(f"エラー: ステータスコード {head_response.status_code}", file=sys.stderr)
|
181
|
+
return None
|
182
|
+
|
183
|
+
# Content-Dispositionヘッダーからファイル名を取得
|
184
|
+
original_filename = None
|
185
|
+
if "content-disposition" in head_response.headers:
|
186
|
+
cd = head_response.headers["content-disposition"]
|
187
|
+
if "filename=" in cd:
|
188
|
+
# 安全なファイル名を抽出(URLエンコードの解除)
|
189
|
+
filename_part = cd.split("filename=")[1].strip('"')
|
190
|
+
|
191
|
+
# filename*=UTF-8 形式のエンコードがある場合
|
192
|
+
if "filename*=UTF-8''" in cd:
|
193
|
+
encoded_part = cd.split("filename*=UTF-8''")[1]
|
194
|
+
# セミコロンやダブルクォートがあれば処理
|
195
|
+
if '"' in encoded_part:
|
196
|
+
encoded_part = encoded_part.split('"')[0]
|
197
|
+
if ';' in encoded_part:
|
198
|
+
encoded_part = encoded_part.split(';')[0]
|
199
|
+
# URLデコードして正しいファイル名を取得
|
200
|
+
original_filename = urllib.parse.unquote(encoded_part)
|
201
|
+
else:
|
202
|
+
# 通常のファイル名(エスケープ処理)
|
203
|
+
original_filename = filename_part.replace('"', '').split(';')[0]
|
204
|
+
|
205
|
+
# 保存用のファイル名を決定
|
206
|
+
if not output:
|
207
|
+
if original_filename:
|
208
|
+
# パスとして安全なファイル名に変換
|
209
|
+
safe_filename = os.path.basename(original_filename)
|
210
|
+
output_filename = safe_filename
|
211
|
+
else:
|
212
|
+
output_filename = f"download_{file_id}"
|
213
|
+
else:
|
214
|
+
output_filename = output
|
215
|
+
|
216
|
+
file_path = os.path.join(output_dir, output_filename)
|
217
|
+
|
218
|
+
# ファイルサイズを取得(プログレスバー用)
|
219
|
+
total_size = int(head_response.headers.get("content-length", 0))
|
220
|
+
|
221
|
+
# ストリーミングダウンロードを開始
|
222
|
+
with client.stream("GET", url) as response:
|
223
|
+
if response.status_code != 200:
|
224
|
+
print(f"エラー: ダウンロード中にエラーが発生しました。ステータスコード: {response.status_code}", file=sys.stderr)
|
225
|
+
return None
|
226
|
+
|
227
|
+
with open(file_path, "wb") as f:
|
228
|
+
if not self.quiet and total_size > 0:
|
229
|
+
progress_bar = tqdm(
|
230
|
+
total=total_size,
|
231
|
+
unit="B",
|
232
|
+
unit_scale=True,
|
233
|
+
desc=f"ダウンロード中: {output_filename}"
|
234
|
+
)
|
235
|
+
|
236
|
+
downloaded = 0
|
237
|
+
|
238
|
+
for chunk in response.iter_bytes():
|
239
|
+
f.write(chunk)
|
240
|
+
if not self.quiet and total_size > 0:
|
241
|
+
downloaded += len(chunk)
|
242
|
+
progress_bar.update(len(chunk))
|
243
|
+
|
244
|
+
if not self.quiet and total_size > 0:
|
245
|
+
progress_bar.close()
|
246
|
+
|
247
|
+
if not self.quiet:
|
248
|
+
print(f"[qdown] ファイルを保存しました: {file_path}")
|
249
|
+
return file_path
|
250
|
+
|
251
|
+
except httpx.RequestError as e:
|
252
|
+
print(f"エラー: リクエストに失敗しました - {e}", file=sys.stderr)
|
253
|
+
return None
|
254
|
+
except Exception as e:
|
255
|
+
print(f"エラー: {e}", file=sys.stderr)
|
256
|
+
return None
|
150
257
|
|
151
258
|
def main():
|
152
259
|
parser = argparse.ArgumentParser(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qdown
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.4
|
4
4
|
Summary: Client for QualitegDrive
|
5
5
|
Home-page: https://github.com/qualiteg/qdown
|
6
6
|
Author: Qualiteg Inc.
|
@@ -22,6 +22,8 @@ Requires-Dist: tqdm (>=4.64.0)
|
|
22
22
|
|
23
23
|
A Python client for downloading files from QualitegDrive operated by Qualiteg Inc.
|
24
24
|
|
25
|
+
[Japanese](README.ja.md)
|
26
|
+
|
25
27
|
# install
|
26
28
|
|
27
29
|
```
|
@@ -0,0 +1,10 @@
|
|
1
|
+
qdown/__init__.py,sha256=rNxBW4Zo6nfWYN2JnLwJVpyGEX3RtBjoE7QlSy0FcxU,2975
|
2
|
+
qdown/gdown.py,sha256=3MpnwlBpEFGi1rdAMzixdBETtw8q5xItaHU1QmtPrEo,6421
|
3
|
+
qdown/qdown.py,sha256=KeU9DN9LdDQwhoPZfDVDz51TlFnjWYUxUpJz8-DtBKI,12432
|
4
|
+
z_examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
z_examples/example.py,sha256=3FQoW22Frgyx5ulb7JOgwgcEBd8K3FI_BuFZP2E54ck,137
|
6
|
+
qdown-1.0.4.dist-info/METADATA,sha256=CVbfXYkssfEtEkbmRxs2Z-zmgUDAPsdd9DmbIZvm4cM,1515
|
7
|
+
qdown-1.0.4.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
8
|
+
qdown-1.0.4.dist-info/entry_points.txt,sha256=4uunDwX_8iGbNA0DKwggOftuKUXvoHxGzvXUd2SW9LM,43
|
9
|
+
qdown-1.0.4.dist-info/top_level.txt,sha256=eVEHrbec1mx2PWv03GzKwFTbdvQqFOAps3GuveF2Ap8,17
|
10
|
+
qdown-1.0.4.dist-info/RECORD,,
|
qdown-1.0.3.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
qdown/__init__.py,sha256=iAC1eU57pgDdmgWVyu2MdOddLXcel2BxR5fH7m2OImg,2983
|
2
|
-
qdown/gdown.py,sha256=3MpnwlBpEFGi1rdAMzixdBETtw8q5xItaHU1QmtPrEo,6421
|
3
|
-
qdown/qdown.py,sha256=NJhqUCgceCd9ojSQCbNuOdNOAVKJywKv_kYohpQblYg,7309
|
4
|
-
z_examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
z_examples/example.py,sha256=3FQoW22Frgyx5ulb7JOgwgcEBd8K3FI_BuFZP2E54ck,137
|
6
|
-
qdown-1.0.3.dist-info/METADATA,sha256=5_W60o0W3VTDOfhj-zDjDDB4xXZhKU-1BcJYYosai5k,1487
|
7
|
-
qdown-1.0.3.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
8
|
-
qdown-1.0.3.dist-info/entry_points.txt,sha256=4uunDwX_8iGbNA0DKwggOftuKUXvoHxGzvXUd2SW9LM,43
|
9
|
-
qdown-1.0.3.dist-info/top_level.txt,sha256=eVEHrbec1mx2PWv03GzKwFTbdvQqFOAps3GuveF2Ap8,17
|
10
|
-
qdown-1.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|