Add IPFS CID display with public gateway links
- Cache detail page shows IPFS section with CID and links to ipfs.io, dweb.link, Cloudflare, and Pinata gateways - Media list cards show purple "IPFS" badge for items with CID - JSON API response includes ipfs_cid field Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
57
server.py
57
server.py
@@ -1714,6 +1714,10 @@ async def cache_detail(content_hash: str, request: Request):
|
||||
elif file_size > 1024:
|
||||
size_str = f"{file_size/1024:.1f} KB"
|
||||
|
||||
# Get IPFS CID from database
|
||||
cache_item = await database.get_cache_item(content_hash)
|
||||
ipfs_cid = cache_item.get("ipfs_cid") if cache_item else None
|
||||
|
||||
# Build media display HTML
|
||||
if media_type == "video":
|
||||
video_src = video_src_for_request(content_hash, request)
|
||||
@@ -1770,7 +1774,47 @@ async def cache_detail(content_hash: str, request: Request):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
|
||||
# Add IPFS section if we have a CID
|
||||
if ipfs_cid:
|
||||
content += f'''
|
||||
<div class="border-t border-dark-500 pt-6 mt-6">
|
||||
<h2 class="text-lg font-semibold text-white mb-4">IPFS</h2>
|
||||
<div class="bg-dark-600 rounded-lg p-4 mb-4">
|
||||
<div class="text-sm text-gray-400 mb-1">Content Identifier (CID)</div>
|
||||
<div class="font-mono text-xs text-gray-200 break-all">{ipfs_cid}</div>
|
||||
</div>
|
||||
<div class="text-sm text-gray-400 mb-2">Public Gateways:</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a href="https://ipfs.io/ipfs/{ipfs_cid}" target="_blank" rel="noopener"
|
||||
class="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded-lg transition-colors">
|
||||
ipfs.io
|
||||
</a>
|
||||
<a href="https://dweb.link/ipfs/{ipfs_cid}" target="_blank" rel="noopener"
|
||||
class="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded-lg transition-colors">
|
||||
dweb.link
|
||||
</a>
|
||||
<a href="https://cloudflare-ipfs.com/ipfs/{ipfs_cid}" target="_blank" rel="noopener"
|
||||
class="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded-lg transition-colors">
|
||||
Cloudflare
|
||||
</a>
|
||||
<a href="https://gateway.pinata.cloud/ipfs/{ipfs_cid}" target="_blank" rel="noopener"
|
||||
class="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded-lg transition-colors">
|
||||
Pinata
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
else:
|
||||
content += '''
|
||||
<div class="border-t border-dark-500 pt-6 mt-6">
|
||||
<h2 class="text-lg font-semibold text-white mb-4">IPFS</h2>
|
||||
<div class="text-gray-400 text-sm">Not yet uploaded to IPFS</div>
|
||||
</div>
|
||||
'''
|
||||
|
||||
content += f'''
|
||||
<!-- Metadata Section -->
|
||||
<div class="border-t border-dark-500 pt-6 mt-6" id="metadata-section"
|
||||
hx-get="/cache/{content_hash}/meta-form" hx-trigger="load" hx-swap="innerHTML">
|
||||
@@ -1783,12 +1827,15 @@ async def cache_detail(content_hash: str, request: Request):
|
||||
|
||||
# JSON response - return metadata
|
||||
meta = await database.load_item_metadata(content_hash, ctx.actor_id if ctx else None)
|
||||
cache_item = await database.get_cache_item(content_hash)
|
||||
ipfs_cid = cache_item.get("ipfs_cid") if cache_item else None
|
||||
file_size = cache_path.stat().st_size
|
||||
media_type = detect_media_type(cache_path)
|
||||
return {
|
||||
"content_hash": content_hash,
|
||||
"size": file_size,
|
||||
"media_type": media_type,
|
||||
"ipfs_cid": ipfs_cid,
|
||||
"meta": meta
|
||||
}
|
||||
|
||||
@@ -3510,6 +3557,11 @@ async def ui_media_list(
|
||||
cache_path = get_cache_path(content_hash)
|
||||
media_type = detect_media_type(cache_path) if cache_path else "unknown"
|
||||
|
||||
# Check IPFS status
|
||||
cache_item = await database.get_cache_item(content_hash)
|
||||
ipfs_cid = cache_item.get("ipfs_cid") if cache_item else None
|
||||
ipfs_badge = '<span class="px-2 py-1 bg-purple-600 text-white text-xs font-medium rounded-full" title="On IPFS">IPFS</span>' if ipfs_cid else ''
|
||||
|
||||
# Format size
|
||||
size = item["size"]
|
||||
if size > 1024*1024:
|
||||
@@ -3523,7 +3575,10 @@ async def ui_media_list(
|
||||
<a href="/ui/cache/{content_hash}" class="block">
|
||||
<div class="bg-dark-700 rounded-lg p-4 hover:bg-dark-600 transition-colors">
|
||||
<div class="flex items-center justify-between gap-2 mb-3">
|
||||
<span class="px-2 py-1 bg-blue-600 text-white text-xs font-medium rounded-full">{media_type}</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-2 py-1 bg-blue-600 text-white text-xs font-medium rounded-full">{media_type}</span>
|
||||
{ipfs_badge}
|
||||
</div>
|
||||
<span class="text-xs text-gray-400">{size_str}</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-400 font-mono mb-3 truncate">{content_hash[:24]}...</div>
|
||||
|
||||
Reference in New Issue
Block a user