Eluza133 commited on
Commit
17567ff
·
verified ·
1 Parent(s): df6920f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -80
app.py CHANGED
@@ -450,8 +450,7 @@ TMA_DASHBOARD_HTML_TEMPLATE = '''
450
  modal.style.display = 'flex';
451
 
452
  if (type !== 'folder' && itemId) {
453
- const downloadUrl = `{{ url_for('download_tma', file_id='__FILE_ID__') }}`.replace('__FILE_ID__', itemId);
454
- downloadBtn.onclick = () => { tmaDownloadFile(downloadUrl); };
455
  downloadBtn.style.display = 'inline-block';
456
  } else {
457
  downloadBtn.style.display = 'none';
@@ -465,7 +464,7 @@ TMA_DASHBOARD_HTML_TEMPLATE = '''
465
  const response = await fetch(srcOrUrl); if (!response.ok) throw new Error(`Ошибка: ${response.statusText}`);
466
  const text = await response.text();
467
  modalContent.innerHTML = `<pre>${text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</pre>`;
468
- } else tmaDownloadFile(srcOrUrl);
469
  } catch (error) { modalContent.innerHTML = `<p>Ошибка предпросмотра: ${error.message}</p>`; }
470
  }
471
 
@@ -478,8 +477,23 @@ TMA_DASHBOARD_HTML_TEMPLATE = '''
478
  document.getElementById('modal-download-btn').style.display = 'none';
479
  }
480
 
481
- function tmaDownloadFile(downloadUrl) {
482
  haptic.impactOccurred('medium');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  if (window.Telegram && window.Telegram.WebApp && Telegram.WebApp.openLink) { Telegram.WebApp.openLink(downloadUrl, {try_instant_view: false}); }
484
  else { window.open(downloadUrl, '_blank'); }
485
  }
@@ -569,8 +583,7 @@ TMA_DASHBOARD_HTML_TEMPLATE = '''
569
  function downloadSingleSelected() {
570
  if (selectedItems.size !== 1) return;
571
  const fileId = selectedItems.values().next().value;
572
- const url = `{{ url_for("download_tma", file_id='__FILE_ID__') }}`.replace('__FILE_ID__', fileId);
573
- tmaDownloadFile(url);
574
  toggleSelectionMode(false);
575
  }
576
 
@@ -755,47 +768,45 @@ def get_file_node_for_admin(tma_user_id_str, file_id):
755
  def download_tma(file_id):
756
  file_node = get_file_node_for_user(file_id)
757
  if not file_node:
758
- return Response("Файл не найден или доступ запрещен!", status=404)
 
 
 
 
 
 
 
 
 
 
 
 
759
 
760
  hf_path = file_node.get('path')
761
  original_filename = file_node.get('original_filename', 'downloaded_file')
762
  if not hf_path:
763
  return Response("Ошибка: Путь к файлу не найден.", status=500)
764
 
765
- file_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/{quote(hf_path)}?download=true"
766
-
767
  try:
768
- req_headers = {}
769
- if HF_TOKEN_READ:
770
- req_headers["Authorization"] = f"Bearer {HF_TOKEN_READ}"
771
-
772
- r = requests.get(file_url, headers=req_headers, stream=True)
773
- r.raise_for_status()
774
-
775
- def generate():
776
- for chunk in r.iter_content(chunk_size=8192):
777
- yield chunk
778
-
779
- response_headers = {
780
- 'Content-Disposition': f'attachment; filename="{quote(original_filename)}"',
781
- 'Content-Type': r.headers.get('content-type', 'application/octet-stream')
782
- }
783
- if 'content-length' in r.headers:
784
- response_headers['Content-Length'] = r.headers['content-length']
785
-
786
- return Response(generate(), headers=response_headers)
787
-
788
- except requests.exceptions.HTTPError as e:
789
- logging.error(f"File not found on Hugging Face (HTTPError): {hf_path} - {e}")
790
- if e.response.status_code == 404:
791
- return Response("Файл не найден на удаленн��м хранилище.", status=404)
792
- else:
793
- return Response(f"Ошибка при доступе к файлу: {e}", status=e.response.status_code)
794
  except Exception as e:
795
- logging.error(f"Error streaming download for {file_id}: {e}")
796
  return Response(f'Ошибка скачивания файла: {e}', status=502)
797
 
798
-
799
  @app.route('/batch_download_tma')
800
  def batch_download_tma():
801
  if 'telegram_user_id' not in session: return Response("Unauthorized", 401)
@@ -1127,13 +1138,33 @@ ADMIN_USER_FILES_HTML = '''
1127
  <span onclick="closeModalManual()" class="modal-close-btn">&times;</span>
1128
  <div class="modal-main-content" id="modalContent"></div>
1129
  <div class="modal-actions">
1130
- <a id="modal-download-btn" class="btn download-btn" style="display: none; width: 80%;">
1131
  <i class="fa-solid fa-download"></i> Download
1132
  </a>
1133
  </div>
1134
  </div>
1135
  </div>
1136
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1137
  async function openModal(srcOrUrl, type, itemId) {
1138
  if (!srcOrUrl) return;
1139
  const modal = document.getElementById('mediaModal');
@@ -1143,8 +1174,7 @@ ADMIN_USER_FILES_HTML = '''
1143
  modal.style.display = 'flex';
1144
 
1145
  if (type !== 'folder' && itemId) {
1146
- const downloadUrl = `{{ url_for('admin_download_file', tma_user_id_str=user_id, file_id='__FILE_ID__') }}`.replace('__FILE_ID__', itemId);
1147
- downloadBtn.href = downloadUrl;
1148
  downloadBtn.style.display = 'inline-block';
1149
  } else {
1150
  downloadBtn.style.display = 'none';
@@ -1158,7 +1188,7 @@ ADMIN_USER_FILES_HTML = '''
1158
  const response = await fetch(srcOrUrl); if (!response.ok) throw new Error(`Error: ${response.statusText}`);
1159
  const text = await response.text();
1160
  modalContent.innerHTML = `<pre>${text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</pre>`;
1161
- } else window.open(srcOrUrl, '_blank');
1162
  } catch (error) { modalContent.innerHTML = `<p>Preview Error: ${error.message}</p>`; }
1163
  }
1164
  function closeModal(event) { if (event.target.id === 'mediaModal') closeModalManual(); }
@@ -1285,46 +1315,12 @@ def admin_user_files(tma_user_id_str):
1285
  def admin_download_file(tma_user_id_str, file_id):
1286
  file_node = get_file_node_for_admin(tma_user_id_str, file_id)
1287
  if not file_node:
1288
- return Response("File not found or access denied!", status=404)
1289
-
1290
- hf_path = file_node.get('path')
1291
- original_filename = file_node.get('original_filename', 'downloaded_file')
1292
- if not hf_path:
1293
- return Response("Error: File path not found.", status=500)
1294
-
1295
- file_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/{quote(hf_path)}?download=true"
1296
-
1297
- try:
1298
- req_headers = {}
1299
- if HF_TOKEN_READ:
1300
- req_headers["Authorization"] = f"Bearer {HF_TOKEN_READ}"
1301
-
1302
- r = requests.get(file_url, headers=req_headers, stream=True)
1303
- r.raise_for_status()
1304
-
1305
- def generate():
1306
- for chunk in r.iter_content(chunk_size=8192):
1307
- yield chunk
1308
-
1309
- response_headers = {
1310
- 'Content-Disposition': f'attachment; filename="{quote(original_filename)}"',
1311
- 'Content-Type': r.headers.get('content-type', 'application/octet-stream')
1312
- }
1313
- if 'content-length' in r.headers:
1314
- response_headers['Content-Length'] = r.headers['content-length']
1315
-
1316
- return Response(generate(), headers=response_headers)
1317
-
1318
- except requests.exceptions.HTTPError as e:
1319
- logging.error(f"Admin: File not found on Hugging Face (HTTPError): {hf_path} - {e}")
1320
- if e.response.status_code == 404:
1321
- return Response("File not found in remote storage.", status=404)
1322
- else:
1323
- return Response(f"Error accessing file: {e}", status=e.response.status_code)
1324
- except Exception as e:
1325
- logging.error(f"Admin: Error streaming download for {file_id}: {e}")
1326
- return Response(f'Error downloading file: {e}', status=502)
1327
 
 
 
 
 
1328
 
1329
  @app.route('/admhosto/text/<tma_user_id_str>/<file_id>')
1330
  @admin_browser_login_required
 
450
  modal.style.display = 'flex';
451
 
452
  if (type !== 'folder' && itemId) {
453
+ downloadBtn.onclick = () => { initiateDownload(itemId); };
 
454
  downloadBtn.style.display = 'inline-block';
455
  } else {
456
  downloadBtn.style.display = 'none';
 
464
  const response = await fetch(srcOrUrl); if (!response.ok) throw new Error(`Ошибка: ${response.statusText}`);
465
  const text = await response.text();
466
  modalContent.innerHTML = `<pre>${text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</pre>`;
467
+ } else initiateDownload(itemId);
468
  } catch (error) { modalContent.innerHTML = `<p>Ошибка предпросмотра: ${error.message}</p>`; }
469
  }
470
 
 
477
  document.getElementById('modal-download-btn').style.display = 'none';
478
  }
479
 
480
+ async function initiateDownload(fileId) {
481
  haptic.impactOccurred('medium');
482
+ try {
483
+ const response = await fetch(`{{ url_for('download_tma', file_id='__FILE_ID__') }}`.replace('__FILE_ID__', fileId));
484
+ const data = await response.json();
485
+ if (data.status === 'success' && data.url) {
486
+ tmaDownloadFile(data.url);
487
+ closeModalManual();
488
+ } else {
489
+ Telegram.WebApp.showAlert(data.message || 'Не удалось создать ссылку для скачивания.');
490
+ }
491
+ } catch (error) {
492
+ Telegram.WebApp.showAlert('Сетевая ошибка при создании ссылки для скачивания.');
493
+ }
494
+ }
495
+
496
+ function tmaDownloadFile(downloadUrl) {
497
  if (window.Telegram && window.Telegram.WebApp && Telegram.WebApp.openLink) { Telegram.WebApp.openLink(downloadUrl, {try_instant_view: false}); }
498
  else { window.open(downloadUrl, '_blank'); }
499
  }
 
583
  function downloadSingleSelected() {
584
  if (selectedItems.size !== 1) return;
585
  const fileId = selectedItems.values().next().value;
586
+ initiateDownload(fileId);
 
587
  toggleSelectionMode(false);
588
  }
589
 
 
768
  def download_tma(file_id):
769
  file_node = get_file_node_for_user(file_id)
770
  if not file_node:
771
+ return jsonify({'status': 'error', 'message': 'Файл не найден или доступ запрещен'}), 404
772
+
773
+ token = uuid.uuid4().hex
774
+ cache.set(f"download_token_{token}", file_node, timeout=60)
775
+ public_url = url_for('public_download', token=token, _external=True)
776
+ return jsonify({'status': 'success', 'url': public_url})
777
+
778
+ @app.route('/public_download/<token>')
779
+ def public_download(token):
780
+ file_node = cache.get(f"download_token_{token}")
781
+ cache.delete(f"download_token_{token}")
782
+ if not file_node:
783
+ return Response("Ссылка для скачивания недействительна или истекла.", status=404)
784
 
785
  hf_path = file_node.get('path')
786
  original_filename = file_node.get('original_filename', 'downloaded_file')
787
  if not hf_path:
788
  return Response("Ошибка: Путь к файлу не найден.", status=500)
789
 
 
 
790
  try:
791
+ local_file_path = hf_hub_download(
792
+ repo_id=REPO_ID,
793
+ filename=hf_path,
794
+ repo_type="dataset",
795
+ token=HF_TOKEN_READ,
796
+ cache_dir=os.path.join(UPLOAD_FOLDER, 'hf_download_cache')
797
+ )
798
+ return send_file(
799
+ local_file_path,
800
+ as_attachment=True,
801
+ download_name=original_filename
802
+ )
803
+ except hf_utils.EntryNotFoundError:
804
+ logging.error(f"File not found on Hugging Face: {hf_path}")
805
+ return Response("Файл не найден на удаленном хранилище.", status=404)
 
 
 
 
 
 
 
 
 
 
 
806
  except Exception as e:
807
+ logging.error(f"Error downloading with token {token} from HF: {e}")
808
  return Response(f'Ошибка скачивания файла: {e}', status=502)
809
 
 
810
  @app.route('/batch_download_tma')
811
  def batch_download_tma():
812
  if 'telegram_user_id' not in session: return Response("Unauthorized", 401)
 
1138
  <span onclick="closeModalManual()" class="modal-close-btn">&times;</span>
1139
  <div class="modal-main-content" id="modalContent"></div>
1140
  <div class="modal-actions">
1141
+ <a id="modal-download-btn" class="btn download-btn" href="javascript:void(0);" style="display: none; width: 80%;">
1142
  <i class="fa-solid fa-download"></i> Download
1143
  </a>
1144
  </div>
1145
  </div>
1146
  </div>
1147
  <script>
1148
+ async function initiateDownload(fileId) {
1149
+ const downloadBtn = document.getElementById('modal-download-btn');
1150
+ const originalHTML = downloadBtn.innerHTML;
1151
+ downloadBtn.innerHTML = '<div class="loading-spinner" style="width:20px; height:20px; border-width:2px;"></div>';
1152
+ try {
1153
+ const response = await fetch(`{{ url_for('admin_download_file', tma_user_id_str=user_id, file_id='__FILE_ID__') }}`.replace('__FILE_ID__', fileId));
1154
+ const data = await response.json();
1155
+ if (data.status === 'success' && data.url) {
1156
+ window.open(data.url, '_blank');
1157
+ } else {
1158
+ alert(data.message || 'Failed to create download link.');
1159
+ }
1160
+ } catch (error) {
1161
+ alert('Network error while creating download link.');
1162
+ } finally {
1163
+ downloadBtn.innerHTML = originalHTML;
1164
+ closeModalManual();
1165
+ }
1166
+ }
1167
+
1168
  async function openModal(srcOrUrl, type, itemId) {
1169
  if (!srcOrUrl) return;
1170
  const modal = document.getElementById('mediaModal');
 
1174
  modal.style.display = 'flex';
1175
 
1176
  if (type !== 'folder' && itemId) {
1177
+ downloadBtn.onclick = () => initiateDownload(itemId);
 
1178
  downloadBtn.style.display = 'inline-block';
1179
  } else {
1180
  downloadBtn.style.display = 'none';
 
1188
  const response = await fetch(srcOrUrl); if (!response.ok) throw new Error(`Error: ${response.statusText}`);
1189
  const text = await response.text();
1190
  modalContent.innerHTML = `<pre>${text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</pre>`;
1191
+ } else initiateDownload(itemId);
1192
  } catch (error) { modalContent.innerHTML = `<p>Preview Error: ${error.message}</p>`; }
1193
  }
1194
  function closeModal(event) { if (event.target.id === 'mediaModal') closeModalManual(); }
 
1315
  def admin_download_file(tma_user_id_str, file_id):
1316
  file_node = get_file_node_for_admin(tma_user_id_str, file_id)
1317
  if not file_node:
1318
+ return jsonify({'status': 'error', 'message': 'File not found or access denied!'}), 404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1319
 
1320
+ token = uuid.uuid4().hex
1321
+ cache.set(f"download_token_{token}", file_node, timeout=60)
1322
+ public_url = url_for('public_download', token=token, _external=True)
1323
+ return jsonify({'status': 'success', 'url': public_url})
1324
 
1325
  @app.route('/admhosto/text/<tma_user_id_str>/<file_id>')
1326
  @admin_browser_login_required