mirror of
https://github.com/ArchiveBox/ArchiveBox.git
synced 2026-09-14 11:06:13 +05:00
release: archivebox 0.9.31rc43
This commit is contained in:
parent
28b890a2c7
commit
082bb50eda
@ -764,9 +764,14 @@ def _serve_responses_path(request, responses_root: Path, rel_path: str, show_ind
|
||||
|
||||
|
||||
def _serve_snapshot_replay(request: HttpRequest, snapshot: Snapshot, path: str = ""):
|
||||
request_config = getattr(request, "archivebox_config", None)
|
||||
if request_config is None:
|
||||
request_config = get_config(resolve_plugins=False)
|
||||
request.archivebox_config = request_config
|
||||
snapshot._runtime_config = request_config
|
||||
rel_path = path or ""
|
||||
is_directory_request = bool(path) and path.endswith("/")
|
||||
show_indexes = bool(request.GET.get("files")) or (get_config().USES_SUBDOMAIN_ROUTING and is_directory_request)
|
||||
show_indexes = bool(request.GET.get("files")) or (request_config.USES_SUBDOMAIN_ROUTING and is_directory_request)
|
||||
if not show_indexes and (not rel_path or rel_path == "index.html"):
|
||||
return SnapshotView.render_live_index(request, snapshot)
|
||||
|
||||
@ -847,16 +852,20 @@ class SnapshotHostView(View):
|
||||
"""Serve snapshot directory contents on <snapshot-subdomain>.<listen_host>/<path>."""
|
||||
|
||||
def get(self, request, snapshot_id: str, path: str = ""):
|
||||
if not request.user.is_authenticated and not get_config().PUBLIC_SNAPSHOTS:
|
||||
request_config = getattr(request, "archivebox_config", None)
|
||||
if request_config is None:
|
||||
request_config = get_config(resolve_plugins=False)
|
||||
request.archivebox_config = request_config
|
||||
if not request.user.is_authenticated and not request_config.PUBLIC_SNAPSHOTS:
|
||||
return _admin_login_redirect_or_forbidden(request)
|
||||
snapshot = _find_snapshot_by_ref(snapshot_id)
|
||||
|
||||
if not snapshot:
|
||||
raise Http404
|
||||
|
||||
canonical_host = get_snapshot_host(str(snapshot.id))
|
||||
canonical_host = get_snapshot_host(str(snapshot.id), config=request_config)
|
||||
if not host_matches(request.get_host(), canonical_host):
|
||||
target = build_snapshot_url(str(snapshot.id), path, request=request)
|
||||
target = build_snapshot_url(str(snapshot.id), path, request=request, config=request_config)
|
||||
if request.META.get("QUERY_STRING"):
|
||||
target = f"{target}?{request.META['QUERY_STRING']}"
|
||||
return redirect(target)
|
||||
@ -868,7 +877,11 @@ class SnapshotReplayView(View):
|
||||
"""Serve snapshot directory contents on a one-domain replay path."""
|
||||
|
||||
def get(self, request, snapshot_id: str, path: str = ""):
|
||||
if not request.user.is_authenticated and not get_config().PUBLIC_SNAPSHOTS:
|
||||
request_config = getattr(request, "archivebox_config", None)
|
||||
if request_config is None:
|
||||
request_config = get_config(resolve_plugins=False)
|
||||
request.archivebox_config = request_config
|
||||
if not request.user.is_authenticated and not request_config.PUBLIC_SNAPSHOTS:
|
||||
return _admin_login_redirect_or_forbidden(request)
|
||||
|
||||
snapshot = _find_snapshot_by_ref(snapshot_id)
|
||||
@ -882,7 +895,11 @@ class OriginalDomainHostView(View):
|
||||
"""Serve responses from the most recent snapshot when using <domain>.<listen_host>/<path>."""
|
||||
|
||||
def get(self, request, domain: str, path: str = ""):
|
||||
if not request.user.is_authenticated and not get_config().PUBLIC_SNAPSHOTS:
|
||||
request_config = getattr(request, "archivebox_config", None)
|
||||
if request_config is None:
|
||||
request_config = get_config(resolve_plugins=False)
|
||||
request.archivebox_config = request_config
|
||||
if not request.user.is_authenticated and not request_config.PUBLIC_SNAPSHOTS:
|
||||
return _admin_login_redirect_or_forbidden(request)
|
||||
return _serve_original_domain_replay(request, domain, path)
|
||||
|
||||
@ -891,7 +908,11 @@ class OriginalDomainReplayView(View):
|
||||
"""Serve original-domain replay content on a one-domain replay path."""
|
||||
|
||||
def get(self, request, domain: str, path: str = ""):
|
||||
if not request.user.is_authenticated and not get_config().PUBLIC_SNAPSHOTS:
|
||||
request_config = getattr(request, "archivebox_config", None)
|
||||
if request_config is None:
|
||||
request_config = get_config(resolve_plugins=False)
|
||||
request.archivebox_config = request_config
|
||||
if not request.user.is_authenticated and not request_config.PUBLIC_SNAPSHOTS:
|
||||
return _admin_login_redirect_or_forbidden(request)
|
||||
return _serve_original_domain_replay(request, domain, path)
|
||||
|
||||
|
||||
@ -61,8 +61,38 @@ def _hash_for_path(document_root: Path, rel_path: str) -> str | None:
|
||||
return file_map.get(rel_path)
|
||||
|
||||
|
||||
def _resolve_archive_path(document_root: str | Path, rel_path: str) -> tuple[Path, str]:
|
||||
rel_path = posixpath.normpath(rel_path).lstrip("/") if rel_path else ""
|
||||
fullpath = Path(safe_join(document_root, rel_path))
|
||||
if os.access(fullpath, os.R_OK):
|
||||
return fullpath, rel_path
|
||||
|
||||
root = Path(document_root)
|
||||
current = root
|
||||
resolved_parts: list[str] = []
|
||||
for part in Path(rel_path).parts:
|
||||
exact = current / part
|
||||
if os.access(exact, os.R_OK):
|
||||
current = exact
|
||||
resolved_parts.append(part)
|
||||
continue
|
||||
|
||||
folded_part = part.casefold()
|
||||
try:
|
||||
match = next((child for child in current.iterdir() if child.name.casefold() == folded_part), None)
|
||||
except OSError:
|
||||
match = None
|
||||
if match is None:
|
||||
return fullpath, rel_path
|
||||
|
||||
current = match
|
||||
resolved_parts.append(match.name)
|
||||
|
||||
return current, posixpath.join(*resolved_parts) if resolved_parts else ""
|
||||
|
||||
|
||||
def _cache_policy(config=None, **config_kwargs) -> str:
|
||||
config = config or get_config(**config_kwargs)
|
||||
config = config or get_config(resolve_plugins=False, **config_kwargs)
|
||||
return "public" if config.PUBLIC_SNAPSHOTS else "private"
|
||||
|
||||
|
||||
@ -139,6 +169,7 @@ def _build_directory_zip_response(
|
||||
*,
|
||||
is_archive_replay: bool,
|
||||
use_async_stream: bool,
|
||||
config=None,
|
||||
) -> StreamingHttpResponse:
|
||||
root_name = _safe_zip_stem(fullpath.name or Path(path).name or "archivebox")
|
||||
sentinel = object()
|
||||
@ -210,7 +241,7 @@ def _build_directory_zip_response(
|
||||
content_type="application/zip",
|
||||
)
|
||||
response.headers["Content-Disposition"] = f'attachment; filename="{root_name}.zip"'
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Last-Modified"] = http_date(fullpath.stat().st_mtime)
|
||||
response.headers["X-Accel-Buffering"] = "no"
|
||||
return _apply_archive_replay_headers(
|
||||
@ -218,6 +249,7 @@ def _build_directory_zip_response(
|
||||
fullpath=fullpath,
|
||||
content_type="application/zip",
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
|
||||
|
||||
@ -640,7 +672,7 @@ def _apply_archive_replay_headers(
|
||||
return response
|
||||
|
||||
response.headers.setdefault("X-Content-Type-Options", "nosniff")
|
||||
config = config or get_config(**config_kwargs)
|
||||
config = config or get_config(resolve_plugins=False, **config_kwargs)
|
||||
response.headers.setdefault("X-ArchiveBox-Security-Mode", config.SERVER_SECURITY_MODE)
|
||||
|
||||
if config.SHOULD_NEUTER_RISKY_REPLAY and _is_risky_replay_document(fullpath, content_type):
|
||||
@ -671,8 +703,11 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
https://github.com/satchamo/django/commit/2ce75c5c4bee2a858c0214d136bfcd351fcde11d
|
||||
"""
|
||||
assert document_root
|
||||
path = posixpath.normpath(path).lstrip("/")
|
||||
fullpath = Path(safe_join(document_root, path))
|
||||
config = getattr(request, "archivebox_config", None)
|
||||
if config is None:
|
||||
config = get_config(resolve_plugins=False)
|
||||
request.archivebox_config = config
|
||||
fullpath, path = _resolve_archive_path(document_root, path)
|
||||
if os.access(fullpath, os.R_OK) and fullpath.is_dir():
|
||||
if request.GET.get("download") == "zip" and show_indexes:
|
||||
return _build_directory_zip_response(
|
||||
@ -680,10 +715,19 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
path,
|
||||
is_archive_replay=is_archive_replay,
|
||||
use_async_stream=hasattr(request, "scope"),
|
||||
config=config,
|
||||
)
|
||||
if show_indexes:
|
||||
response = _render_directory_index(request, path, fullpath)
|
||||
return _apply_archive_replay_headers(response, fullpath=fullpath, content_type="text/html", is_archive_replay=is_archive_replay)
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Last-Modified"] = http_date(fullpath.stat().st_mtime)
|
||||
return _apply_archive_replay_headers(
|
||||
response,
|
||||
fullpath=fullpath,
|
||||
content_type="text/html",
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
raise Http404(_("Directory indexes are not allowed here."))
|
||||
if not os.access(fullpath, os.R_OK):
|
||||
raise Http404(_("“%(path)s” does not exist") % {"path": fullpath})
|
||||
@ -704,9 +748,15 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
if etag in inm_list or etag.strip('"') in [i.strip('"') for i in inm_list]:
|
||||
not_modified = HttpResponseNotModified()
|
||||
not_modified.headers["ETag"] = etag
|
||||
not_modified.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
not_modified.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
not_modified.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
return _apply_archive_replay_headers(not_modified, fullpath=fullpath, content_type="", is_archive_replay=is_archive_replay)
|
||||
return _apply_archive_replay_headers(
|
||||
not_modified,
|
||||
fullpath=fullpath,
|
||||
content_type="",
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
|
||||
content_type, encoding = mimetypes.guess_type(str(fullpath))
|
||||
content_type = content_type or "application/octet-stream"
|
||||
@ -739,6 +789,7 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
fullpath=fullpath,
|
||||
content_type=content_type,
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
|
||||
# Wrap text-like outputs in HTML when explicitly requested for iframe previewing.
|
||||
@ -752,9 +803,9 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
response.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if etag:
|
||||
response.headers["ETag"] = etag
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Content-Disposition"] = f'inline; filename="{fullpath.name}"'
|
||||
if encoding:
|
||||
response.headers["Content-Encoding"] = encoding
|
||||
@ -763,6 +814,7 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
fullpath=fullpath,
|
||||
content_type="text/html; charset=utf-8",
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
@ -779,9 +831,9 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
response.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if etag:
|
||||
response.headers["ETag"] = etag
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Content-Disposition"] = f'inline; filename="{fullpath.name}"'
|
||||
if encoding:
|
||||
response.headers["Content-Encoding"] = encoding
|
||||
@ -790,6 +842,7 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
fullpath=fullpath,
|
||||
content_type="text/html; charset=utf-8",
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
@ -806,9 +859,9 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
response.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if etag:
|
||||
response.headers["ETag"] = etag
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Content-Disposition"] = f'inline; filename="{fullpath.stem}.html"'
|
||||
response.headers["X-Content-Type-Options"] = "nosniff"
|
||||
response.headers["Content-Security-Policy"] = (
|
||||
@ -846,9 +899,9 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
response.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if etag:
|
||||
response.headers["ETag"] = etag
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Content-Disposition"] = f'inline; filename="{fullpath.name}"'
|
||||
if encoding:
|
||||
response.headers["Content-Encoding"] = encoding
|
||||
@ -857,15 +910,16 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
fullpath=fullpath,
|
||||
content_type="text/html; charset=utf-8",
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
if escaped_count and escaped_count > tag_count * 2:
|
||||
response = HttpResponse(decoded, content_type=content_type)
|
||||
response.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if etag:
|
||||
response.headers["ETag"] = etag
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Content-Disposition"] = f'inline; filename="{fullpath.name}"'
|
||||
if encoding:
|
||||
response.headers["Content-Encoding"] = encoding
|
||||
@ -874,6 +928,7 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
fullpath=fullpath,
|
||||
content_type=content_type,
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
@ -884,9 +939,9 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
response.headers["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if etag:
|
||||
response.headers["ETag"] = etag
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=31536000, immutable"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=31536000, immutable"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"{_cache_policy()}, max-age=60, stale-while-revalidate=300"
|
||||
response.headers["Cache-Control"] = f"{_cache_policy(config=config)}, max-age=60, stale-while-revalidate=300"
|
||||
if is_text_like:
|
||||
response.headers["Content-Disposition"] = f'inline; filename="{fullpath.name}"'
|
||||
if content_type.startswith("image/"):
|
||||
@ -918,7 +973,13 @@ def serve_static_with_byterange_support(request, path, document_root=None, show_
|
||||
response.status_code = 206
|
||||
if encoding:
|
||||
response.headers["Content-Encoding"] = encoding
|
||||
return _apply_archive_replay_headers(response, fullpath=fullpath, content_type=content_type, is_archive_replay=is_archive_replay)
|
||||
return _apply_archive_replay_headers(
|
||||
response,
|
||||
fullpath=fullpath,
|
||||
content_type=content_type,
|
||||
is_archive_replay=is_archive_replay,
|
||||
config=config,
|
||||
)
|
||||
|
||||
|
||||
def serve_static(request, path, **kwargs):
|
||||
|
||||
@ -15,7 +15,11 @@
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
a { color: inherit; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.container-fluid { width: 100%; margin: 0 auto; padding: 0 12px; }
|
||||
@ -33,6 +37,8 @@
|
||||
.alert { padding: 6px 10px; border-radius: 6px; background: #f5f5f5; color: #333; }
|
||||
header {
|
||||
background-color: #aa1e55;
|
||||
order: 1;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
small {
|
||||
font-weight: 200;
|
||||
@ -436,6 +442,8 @@
|
||||
height: calc(100vh - 210px);
|
||||
border-top: 3px solid #aa1e55;
|
||||
overflow: hidden;
|
||||
order: 2;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#main-frame-wrapper iframe {
|
||||
width: 100%;
|
||||
@ -963,6 +971,48 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main-frame-wrapper" class="full-page-wrapper">
|
||||
<iframe id="main-frame"
|
||||
sandbox="allow-same-origin allow-top-navigation-by-user-activation allow-scripts allow-forms"
|
||||
class="full-page-iframe"
|
||||
src="about:blank"
|
||||
data-default-src="{% if best_result.path %}{% snapshot_preview_url snapshot best_result.path %}{% else %}{% snapshot_base_url snapshot %}/?files=1{% endif %}"
|
||||
name="preview"
|
||||
loading="eager"
|
||||
fetchpriority="high"></iframe>
|
||||
</div>
|
||||
<script>
|
||||
(() => {
|
||||
const frame = document.getElementById('main-frame')
|
||||
if (!frame) return
|
||||
const snapshotBaseUrlEarly = "{% snapshot_base_url snapshot %}"
|
||||
const snapshotFilesUrlEarly = `${snapshotBaseUrlEarly}/?files=1`
|
||||
const defaultSrc = frame.dataset.defaultSrc || snapshotFilesUrlEarly
|
||||
const rawHash = window.location.hash ? window.location.hash.slice(1) : ''
|
||||
|
||||
function resolveEarlyPreviewUrl(raw) {
|
||||
if (!raw) return defaultSrc
|
||||
let value = raw
|
||||
try {
|
||||
value = decodeURIComponent(value)
|
||||
} catch (err) {}
|
||||
if (value === 'all') return snapshotFilesUrlEarly
|
||||
if (value.startsWith('http://') || value.startsWith('https://')) return value
|
||||
if (value.startsWith('//')) return window.location.protocol + value
|
||||
value = value.replace(/^\/+/, '')
|
||||
return `${snapshotBaseUrlEarly}/${value}`
|
||||
}
|
||||
|
||||
const target = resolveEarlyPreviewUrl(rawHash)
|
||||
if (target) {
|
||||
if (target.endsWith('.pdf')) {
|
||||
frame.removeAttribute('sandbox')
|
||||
}
|
||||
frame.src = target
|
||||
frame.dataset.initialSrc = target
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
<header>
|
||||
<div class="header-top">
|
||||
<div class="header-nav">
|
||||
@ -1174,19 +1224,6 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="main-frame-wrapper" class="full-page-wrapper">
|
||||
<iframe id="main-frame"
|
||||
sandbox="allow-same-origin allow-top-navigation-by-user-activation allow-scripts allow-forms"
|
||||
class="full-page-iframe"
|
||||
src="about:blank"
|
||||
data-default-src="{% if best_result.path %}{% snapshot_preview_url snapshot best_result.path %}{% else %}{% snapshot_base_url snapshot %}/?files=1{% endif %}"
|
||||
name="preview"
|
||||
loading="eager"
|
||||
fetchpriority="high"></iframe>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="{% static 'jquery.min.js' %}" type="text/javascript"></script>
|
||||
|
||||
<script>
|
||||
@ -1398,7 +1435,17 @@
|
||||
jQuery('.selected-card').removeClass('selected-card')
|
||||
jQuery(card).closest('.thumb-card').addClass('selected-card')
|
||||
|
||||
const iframe_elem = ensureMainFrame(true)
|
||||
const nextSrc = isSnapshotRootPreview(target) ? snapshotFilesUrl : target
|
||||
const existingFrame = document.getElementById('main-frame')
|
||||
let currentSrc = ''
|
||||
try {
|
||||
currentSrc = existingFrame ? new URL(existingFrame.getAttribute('src') || existingFrame.src || '', window.location.href).href : ''
|
||||
} catch (err) {}
|
||||
let nextSrcAbs = nextSrc
|
||||
try {
|
||||
nextSrcAbs = new URL(nextSrc, window.location.href).href
|
||||
} catch (err) {}
|
||||
const iframe_elem = ensureMainFrame(currentSrc !== nextSrcAbs)
|
||||
if (target.endsWith('.pdf')) {
|
||||
iframe_elem.removeAttribute('sandbox')
|
||||
} else {
|
||||
@ -1408,7 +1455,9 @@
|
||||
window.location.hash = getPreviewHashValueFromHref(rawTarget)
|
||||
}
|
||||
|
||||
iframe_elem.src = isSnapshotRootPreview(target) ? snapshotFilesUrl : target
|
||||
if (currentSrc !== nextSrcAbs) {
|
||||
iframe_elem.src = nextSrc
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "archivebox",
|
||||
"version": "0.9.31rc42",
|
||||
"version": "0.9.31rc43",
|
||||
"repository": "github:ArchiveBox/ArchiveBox",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "archivebox"
|
||||
version = "0.9.31rc42"
|
||||
version = "0.9.31rc43"
|
||||
requires-python = ">=3.13"
|
||||
description = "Self-hosted internet archiving solution."
|
||||
authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}]
|
||||
@ -79,9 +79,9 @@ dependencies = [
|
||||
### Extractor dependencies (optional binaries detected at runtime via shutil.which)
|
||||
### Binary/Package Management
|
||||
"abxbus>=2.5.4", # EventBus API
|
||||
"abxpkg>=1.10.32", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm
|
||||
"abx-plugins>=1.10.97", # shared ArchiveBox plugin package with Chrome/Puppeteer dependency wiring
|
||||
"abx-dl>=1.10.97", # shared ArchiveBox downloader package with blocking install preflight
|
||||
"abxpkg>=1.10.34", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm
|
||||
"abx-plugins>=1.10.99", # shared ArchiveBox plugin package with Chrome/Puppeteer dependency wiring
|
||||
"abx-dl>=1.10.99", # shared ArchiveBox downloader package with blocking install preflight
|
||||
### UUID7 backport for Python <3.14
|
||||
"uuid7>=0.1.0; python_version < '3.14'", # provides the uuid_extensions module on Python 3.13
|
||||
]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user