j
This commit is contained in:
@@ -353,7 +353,7 @@
|
|||||||
"filedot\\.(xyz|to|top)/([0-9a-zA-Z]{12})"
|
"filedot\\.(xyz|to|top)/([0-9a-zA-Z]{12})"
|
||||||
],
|
],
|
||||||
"regexp": "filedot\\.(xyz|to|top)/([0-9a-zA-Z]{12})",
|
"regexp": "filedot\\.(xyz|to|top)/([0-9a-zA-Z]{12})",
|
||||||
"status": false
|
"status": true
|
||||||
},
|
},
|
||||||
"filefactory": {
|
"filefactory": {
|
||||||
"name": "filefactory",
|
"name": "filefactory",
|
||||||
@@ -786,7 +786,7 @@
|
|||||||
"(upl\\.wf/d/[0-9a-zA-Z]+)"
|
"(upl\\.wf/d/[0-9a-zA-Z]+)"
|
||||||
],
|
],
|
||||||
"regexp": "((world\\-files\\.com/[0-9a-zA-Z]{12}))|((upl\\.wf/d/[0-9a-zA-Z]+))",
|
"regexp": "((world\\-files\\.com/[0-9a-zA-Z]{12}))|((upl\\.wf/d/[0-9a-zA-Z]+))",
|
||||||
"status": false,
|
"status": true,
|
||||||
"hardRedirect": [
|
"hardRedirect": [
|
||||||
"world\\-files\\.com/([0-9a-zA-Z]{12})"
|
"world\\-files\\.com/([0-9a-zA-Z]{12})"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -277,14 +277,54 @@ class ZeroTier(Store):
|
|||||||
debug(f"Hydrus get_file failed: {exc}")
|
debug(f"Hydrus get_file failed: {exc}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# remote storage: try metadata endpoint
|
# remote storage: return download URL
|
||||||
res = self._request_remote("GET", f"/files/{file_hash}")
|
base = self._ensure_client()
|
||||||
if isinstance(res, dict):
|
if not base or not isinstance(base, str):
|
||||||
# remote server returns a 'path' to the file (server-local path)
|
return None
|
||||||
p = res.get("path") or res.get("file") or None
|
|
||||||
if isinstance(p, str) and p.startswith("http"):
|
url = f"{base.rstrip('/')}/files/raw/{file_hash}"
|
||||||
return p
|
if self._api_key:
|
||||||
return p
|
sep = "&" if "?" in url else "?"
|
||||||
|
url += f"{sep}api_key={self._api_key}"
|
||||||
|
return url
|
||||||
|
|
||||||
|
def download_to_temp(self, file_hash: str, temp_root: Optional[Path] = None) -> Optional[Path]:
|
||||||
|
"""Download a file from the remote peer to a local temporary file."""
|
||||||
|
import os
|
||||||
|
import httpx
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
if self._service == "hydrus":
|
||||||
|
return None
|
||||||
|
|
||||||
|
url = self.get_file(file_hash)
|
||||||
|
if not url or not isinstance(url, str) or not url.startswith("http"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use provided temp_root or system temp
|
||||||
|
if temp_root:
|
||||||
|
temp_root.mkdir(parents=True, exist_ok=True)
|
||||||
|
fd, tmp_path = tempfile.mkstemp(dir=str(temp_root), suffix=".tmp")
|
||||||
|
else:
|
||||||
|
fd, tmp_path = tempfile.mkstemp(suffix=".tmp")
|
||||||
|
|
||||||
|
os_fd = os.fdopen(fd, 'wb')
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
if self._api_key:
|
||||||
|
headers["X-API-Key"] = self._api_key
|
||||||
|
|
||||||
|
with httpx.stream("GET", url, headers=headers, timeout=self._timeout) as r:
|
||||||
|
r.raise_for_status()
|
||||||
|
for chunk in r.iter_bytes():
|
||||||
|
os_fd.write(chunk)
|
||||||
|
|
||||||
|
os_fd.close()
|
||||||
|
return Path(tmp_path)
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
debug(f"ZeroTier download_to_temp failed for {file_hash}: {exc}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def add_file(self, file_path: Path, **kwargs: Any) -> Optional[str]:
|
def add_file(self, file_path: Path, **kwargs: Any) -> Optional[str]:
|
||||||
|
|||||||
@@ -1017,10 +1017,10 @@ class Add_File(Cmdlet):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# PRIORITY 1b: Try hash+store from result dict (fetch from backend)
|
# PRIORITY 1b: Try hash+store from result (fetch from backend)
|
||||||
if isinstance(result, dict):
|
r_hash = get_field(result, "hash") or get_field(result, "file_hash")
|
||||||
r_hash = result.get("hash")
|
r_store = get_field(result, "store")
|
||||||
r_store = result.get("store")
|
|
||||||
if r_hash and r_store:
|
if r_hash and r_store:
|
||||||
try:
|
try:
|
||||||
store = store_instance
|
store = store_instance
|
||||||
@@ -1130,7 +1130,6 @@ class Add_File(Cmdlet):
|
|||||||
|
|
||||||
return files_info
|
return files_info
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _validate_source(media_path: Optional[Path], allow_all_extensions: bool = False) -> bool:
|
def _validate_source(media_path: Optional[Path], allow_all_extensions: bool = False) -> bool:
|
||||||
"""Validate that the source file exists and is supported.
|
"""Validate that the source file exists and is supported.
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ def create_app():
|
|||||||
"Flask not installed. Install with: pip install flask flask-cors"
|
"Flask not installed. Install with: pip install flask flask-cors"
|
||||||
)
|
)
|
||||||
|
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify, send_file
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -325,12 +325,32 @@ def create_app():
|
|||||||
logger.error(f"Get metadata error: {e}", exc_info=True)
|
logger.error(f"Get metadata error: {e}", exc_info=True)
|
||||||
return jsonify({"error": f"Failed to get metadata: {str(e)}"}), 500
|
return jsonify({"error": f"Failed to get metadata: {str(e)}"}), 500
|
||||||
|
|
||||||
|
@app.route("/files/raw/<file_hash>", methods=["GET"])
|
||||||
|
@require_auth()
|
||||||
|
@require_storage()
|
||||||
|
def download_file(file_hash: str):
|
||||||
|
"""Download a raw file by hash."""
|
||||||
|
try:
|
||||||
|
search_db = get_db(STORAGE_PATH)
|
||||||
|
db = search_db.db
|
||||||
|
if not db:
|
||||||
|
return jsonify({"error": "Database unavailable"}), 500
|
||||||
|
|
||||||
|
file_path = db.search_hash(file_hash)
|
||||||
|
|
||||||
|
if not file_path or not file_path.exists():
|
||||||
|
return jsonify({"error": "File not found"}), 404
|
||||||
|
|
||||||
|
return send_file(file_path)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Download error: {e}", exc_info=True)
|
||||||
|
return jsonify({"error": f"Download failed: {str(e)}"}), 500
|
||||||
|
|
||||||
@app.route("/files/index", methods=["POST"])
|
@app.route("/files/index", methods=["POST"])
|
||||||
@require_auth()
|
@require_auth()
|
||||||
@require_storage()
|
@require_storage()
|
||||||
def index_file():
|
def index_file():
|
||||||
"""Index a new file in the storage."""
|
"""Index a new file in the storage."""
|
||||||
from API.folder import API_folder_store
|
|
||||||
from SYS.utils import sha256_file
|
from SYS.utils import sha256_file
|
||||||
|
|
||||||
data = request.get_json() or {}
|
data = request.get_json() or {}
|
||||||
@@ -347,7 +367,11 @@ def create_app():
|
|||||||
if not file_path.exists():
|
if not file_path.exists():
|
||||||
return jsonify({"error": "File does not exist"}), 404
|
return jsonify({"error": "File does not exist"}), 404
|
||||||
|
|
||||||
with API_folder_store(STORAGE_PATH) as db:
|
search_db = get_db(STORAGE_PATH)
|
||||||
|
db = search_db.db
|
||||||
|
if not db:
|
||||||
|
return jsonify({"error": "Database unavailable"}), 500
|
||||||
|
|
||||||
db.get_or_create_file_entry(file_path)
|
db.get_or_create_file_entry(file_path)
|
||||||
|
|
||||||
if tags:
|
if tags:
|
||||||
|
|||||||
Reference in New Issue
Block a user