qdown 1.0.3__tar.gz → 1.0.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qdown
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Client for QualitegDrive
5
5
  Home-page: https://github.com/qualiteg/qdown
6
6
  Author: Qualiteg Inc.
@@ -20,6 +20,8 @@ Description-Content-Type: text/markdown
20
20
 
21
21
  A Python client for downloading files from QualitegDrive operated by Qualiteg Inc.
22
22
 
23
+ [Japanese](README.ja.md)
24
+
23
25
  # install
24
26
 
25
27
  ```
@@ -2,6 +2,8 @@
2
2
 
3
3
  A Python client for downloading files from QualitegDrive operated by Qualiteg Inc.
4
4
 
5
+ [Japanese](README.ja.md)
6
+
5
7
  # install
6
8
 
7
9
  ```
@@ -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 asyncio.run(client.download_by_file_id(
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
+ )
@@ -147,6 +147,132 @@ 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
+ if "Name or service not known" in str(e):
254
+ print("WSLで実行しているとき、このDNSエラーに遭遇した場合は以下をお試しください")
255
+ print("If you are running this in WSL, please try setting up DNS as follows:", file=sys.stderr)
256
+ print("STEP 1: Disable the automatic DNS configuration in WSL2", file=sys.stderr)
257
+ print("In WSL bash, run the following to prevent automatic generation of resolv.conf:", file=sys.stderr)
258
+ print('sudo sh -c \'cat > /etc/wsl.conf << EOF', file=sys.stderr)
259
+ print('[user]', file=sys.stderr)
260
+ print('default=mlu', file=sys.stderr)
261
+ print('[network]', file=sys.stderr)
262
+ print('generateResolvConf = false', file=sys.stderr)
263
+ print('EOF\'', file=sys.stderr)
264
+ print("STEP 2: Restart WSL from Windows", file=sys.stderr)
265
+ print('wsl --shutdown', file=sys.stderr)
266
+ print("STEP 3: After restarting WSL, run the following in the shell:", file=sys.stderr)
267
+ print('sudo sh -c \'cat > /etc/resolv.conf << EOF', file=sys.stderr)
268
+ print('nameserver 8.8.8.8', file=sys.stderr)
269
+ print('nameserver 8.8.4.4', file=sys.stderr)
270
+ print('EOF\'', file=sys.stderr)
271
+ return None
272
+ except Exception as e:
273
+ print(f"エラー: {e}", file=sys.stderr)
274
+ return None
275
+
150
276
 
151
277
  def main():
152
278
  parser = argparse.ArgumentParser(
@@ -182,4 +308,4 @@ def main():
182
308
 
183
309
 
184
310
  if __name__ == "__main__":
185
- main()
311
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qdown
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Client for QualitegDrive
5
5
  Home-page: https://github.com/qualiteg/qdown
6
6
  Author: Qualiteg Inc.
@@ -20,6 +20,8 @@ Description-Content-Type: text/markdown
20
20
 
21
21
  A Python client for downloading files from QualitegDrive operated by Qualiteg Inc.
22
22
 
23
+ [Japanese](README.ja.md)
24
+
23
25
  # install
24
26
 
25
27
  ```
@@ -2,7 +2,6 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  from setuptools import setup, find_packages
5
- import os
6
5
 
7
6
  # README.mdの内容を読み込む
8
7
  with open("README.md", "r", encoding="utf-8") as fh:
@@ -10,7 +9,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
10
9
 
11
10
  setup(
12
11
  name="qdown",
13
- version="1.0.3", # バージョン更新
12
+ version="1.0.5",
14
13
  description="Client for QualitegDrive",
15
14
  long_description=long_description,
16
15
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes