Spaces:
Running
Running
<html> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<head> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"> | |
<link rel="preload" href="{{ url_for('static', filename='eye.gif') }}" as="image"> | |
<link rel="icon" type="image/png" href="https://i.ibb.co/gvKPXJD/eye.gif"> | |
<title>{{ page_title|safe }}</title> | |
<style> | |
body { | |
justify-content: center; | |
background-color: black; | |
display: flex; | |
align-items:center; | |
height: 100vh; | |
margin: auto; | |
} | |
/* Webkit browsers like Chrome, Safari */ | |
::-webkit-scrollbar { | |
width: 10px; | |
border-radius: 5px; | |
} | |
::-webkit-scrollbar-thumb { | |
background: black; | |
border-radius: 5px; | |
} | |
::-webkit-scrollbar-thumb:hover { | |
background: black; | |
} | |
/* Firefox */ | |
* { | |
scrollbar-width: thin; | |
scrollbar-color: black yellow; | |
} | |
h3 { | |
margin-bottom: 0px; | |
margin-top: 0px ; | |
border-bottom: 2px solid yellow; | |
color:rgb(53, 53, 53); | |
font-family: 'Helvetica'; font-weight: 50; | |
} | |
.pulse { | |
width: 40px; | |
height: 40px; | |
border-radius: 50%; | |
position: absolute; | |
background-color: yellow; | |
opacity: 0.5; | |
animation: pulse-animation 5s infinite; | |
margin-left: -20px; | |
margin-top: -20px; | |
} | |
.dot { | |
border-style: solid; | |
border-width: 2px; | |
border-color: black; | |
width: 5px; | |
height: 5px; | |
border-radius: 50%; | |
position: absolute; | |
background-color: yellow; | |
margin-left: -4.5px; | |
margin-top: -4.5px; | |
} | |
@keyframes pulse-animation { | |
0% { transform: scale(0.1); opacity: 0.4; } | |
100% { transform: scale(3); opacity: 0; } | |
} | |
.flex-container { | |
display: flex; | |
justify-content: left; | |
align-items: top; | |
} | |
.outer-container { | |
display: inline-block; | |
justify-content: left; | |
max-width: 70vw; | |
} | |
#feed-div { | |
display: flex; | |
justify-content: right; | |
width: 90%; | |
height: 90%; | |
position: relative; | |
margin-right: 20px; | |
} | |
h1 { | |
margin: 0px; | |
margin-top: 20px; | |
} | |
.feed { | |
transition: opacity 0.3s ease; | |
width: 100%; | |
height: 100%; | |
max-height: 80vh; | |
border-radius: 5px; | |
} | |
.map-div { | |
position: relative; | |
width: 280px; | |
height: 190px; | |
margin-top: 3%; | |
margin-bottom: 3%; | |
box-sizing: border-box; | |
} | |
.info { | |
cursor: default; | |
display: flex; | |
flex-direction: column; | |
align-items: flex-start; | |
width: 300px; | |
transition 0.3s ease; | |
} | |
#info { | |
transition 0.5s ease; | |
} | |
#info-text { | |
margin-top: 20px; | |
margin-bottom: 20px; | |
} | |
a:hover { | |
background-color: yellow; | |
color: black; | |
transition: 0.5s ease; | |
} | |
a { | |
background-color: transparent; | |
border-radius: 5px; | |
text-decoration: none; | |
color:rgb(53, 53, 53); | |
transition: 0.5s ease; | |
} | |
.hoverButton { | |
color: rgb(53,53,53); | |
} | |
.tag { | |
font-family: 'Helvetica'; | |
font-weight: 50; | |
margin: auto; | |
color:rgb(53,53,53); | |
} | |
#share { | |
margin: auto; | |
margin-left: 10px; | |
color: yellow; | |
transition: 0.3s ease; | |
} | |
#share:hover { | |
opacity: 0.5; | |
} | |
#show-more { | |
cursor: pointer; | |
} | |
#additional-info { | |
display: block; | |
height: 0px; | |
overflow: hidden; | |
transition: height 0.3s ease; | |
} | |
#additional-info.expanded { | |
height: auto; | |
} | |
@media only screen and (orientation: portrait) { | |
.body { | |
height: 85vh; | |
} | |
h1 { | |
margin-top: 20px ; | |
} | |
.flex-container { | |
flex-direction: column; | |
align-items: left; | |
} | |
.map-div { | |
width: 100%; | |
height: 100%; | |
} | |
.outer-container { | |
max-width: 85vw; | |
} | |
#feed-div { | |
justify-content: left; | |
width: 100%; | |
max-height: 45%; | |
margin-right: 0; | |
} | |
.feed { | |
height: 100%; | |
width: 100%; | |
max-height: 100%; | |
} | |
} | |
</style> | |
</head> | |
<body style="background-color: black;"> | |
<div class="outer-container"> | |
<div class="flex-container"> | |
<div id="feed-div"> | |
<img id="feed" class="feed" src="static/eye.gif" /> | |
</div> | |
<div class="info" id="info"> | |
<h1 id="country" style="color:rgb(53, 53, 53); margin-top: 10px; font-family: 'Helvetica'; font-weight: 50; margin-bottom: 10px;"> searching...</h1> | |
<a href="{{ ip_link }}" target="_blank"> <h3 style="border-bottom: 2px solid yellow;" id="location-name">{{ page_title|safe }}</h3></a> | |
<div style="display: flex; margin-top: 22px; margin-bottom: 0%;"> | |
<a href="?new=true" style="margin-right: 10px; display: inline-block;"> | |
<button class="hoverButton" style="border-radius: 5px; border: 2px solid yellow; background-color: transparent; padding: 10px;"> | |
another | |
</button> | |
</a> | |
<!--<a class="abortButton" href="?new=false&id={{ id }}" id="refreshSameFeedButton" style="display: inline-block;">--> | |
<a class="abortButton" href="?new=false&id={{ id }}" id="refreshSameFeedButton" style="display: inline-block;"> | |
<button class="hoverButton" style="border-radius: 5px; border: 2px solid rgb(53, 53, 53); background-color: transparent; padding: 10px;"> | |
refresh | |
</button> | |
</a> | |
<i id="share" class="fa-solid fa-link" data-id="{{ id }}"></i> | |
<p id="copied" class="tag" style="visibility: hidden;">copied</p> | |
</div> | |
<p id="info-text" style="color:rgb(53, 53, 53); font-family: 'Helvetica'; font-weight: 50;"> | |
time: <span id="time"></span><br> | |
<span id="additional-info"> | |
owner: {{ owner }}<br> | |
ip: {{ ip }}<br> | |
lat, lon: {{ loc }} | |
</span> | |
<span id="show-more">more <i style="margin-bottom:20px; color:rgb(53, 53, 53);" id="more-button" class="fa-solid fa-caret-down"></i></span> | |
<span class="tag"><br>a brayden moore website<br></span> | |
thanks for visiting<br> | |
<a href="https://huggingface.co/spaces/BraydenMoore/a-random-unsecured-camera/tree/main" target="_blank">see the code</a> | |
</p> | |
<!-- | |
<div class="map-div"> | |
<img id="map" src="{{ url_for('static', filename='map_populated.png') }}" style="width: 100%; height: 100%;" /> | |
<div class="dot" style="left: {{ X }}%; top: {{ Y }}%;"></div> | |
<div class="pulse" style="left: {{ X }}%; top: {{ Y }}%;"></div> | |
</div> | |
--> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Handle feed load and refresh | |
let loadingGif = "{{ url_for('static', filename='eye.gif') }}"; | |
let currentFeed; | |
let firstLoad = true; | |
document.addEventListener("DOMContentLoaded", function() { | |
const feed = document.getElementById("feed"); | |
feed.style.width = "80px"; | |
feed.style.height = "50px"; | |
feed.src = loadingGif; | |
feed.style.opacity = "0.2"; | |
const infoDiv = document.getElementById("info"); | |
const infoText = document.getElementById("info-text"); | |
infoText.style.opacity = "0"; | |
const countryElement = document.getElementById("country"); | |
const locationName = document.getElementById('location-name'); | |
locationName.textContent = "{{ page_title|safe }}"; | |
const newUrl = "{{ url|safe }}"; | |
let contentTypeChecked = false; | |
let isJpeg = false; | |
function refreshImage() { | |
if (!isJpeg && !contentTypeChecked) { | |
let xhr = new XMLHttpRequest(); | |
xhr.open('HEAD', newUrl, true); | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState === 4 && xhr.status === 200) { | |
if (xhr.getResponseHeader('Content-Type') === 'image/jpeg') { | |
img.src = newUrl + "?r=" + new Date().getTime(); | |
if (firstLoad){ | |
countryElement.textContent = "connecting..."; | |
} | |
isJpeg = true; | |
contentTypeChecked = true; | |
} | |
} | |
}; | |
xhr.send(); | |
} else if (isJpeg && contentTypeChecked) { | |
img.src = newUrl + "?r=" + new Date().getTime(); | |
} | |
} | |
const img = new Image(); | |
img.onload = function() { | |
if (firstLoad) { | |
infoDiv.style.opacity = "0"; | |
} | |
firstLoad = false; | |
old = newUrl; | |
setTimeout(() => { | |
feed.src = this.src; | |
locationName.textContent = "{{ name|safe }}"; | |
feed.style.width = "100%"; | |
feed.style.height = "70%"; | |
feed.style.opacity = "1"; | |
infoDiv.style.opacity = "1"; | |
}, 100); | |
const infoText = document.getElementById("info-text"); | |
infoText.style.opacity = "1"; | |
setTimeout(refreshImage, 500); | |
country.textContent = "{{ country }}" | |
}; | |
img.onerror = function(event) { | |
feed.style.width = "80px"; | |
feed.style.height = "50px"; | |
feed.src = loadingGif; | |
feed.style.opacity = "0.2"; | |
infoText.style.opacity = "0"; | |
locationName.textContent = "{{ page_title|safe }}"; | |
console.log("Image loading failed:", event); | |
const urlParams = new URLSearchParams(window.location.search); | |
if (urlParams.get('new') === 'false') { | |
countryElement.textContent = "couldn't connect."; | |
} | |
else { | |
window.location.href = "?new=true"; | |
} | |
}; | |
img.src = newUrl; | |
}); | |
// Time count | |
document.addEventListener("DOMContentLoaded", function() { | |
const timezone = "{{ timezone }}"; | |
setInterval(() => { | |
const now = new Date(); | |
const options = { | |
timeZone: timezone, | |
hour: '2-digit', | |
minute: '2-digit', | |
second: '2-digit', | |
hour12: true | |
}; | |
const timeString = now.toLocaleTimeString('en-US', options); | |
document.getElementById("time").textContent = timeString; | |
}, 200); | |
}); | |
// Copy link | |
document.addEventListener("DOMContentLoaded", function() { | |
const shareIcon = document.getElementById("share"); | |
const copiedText = document.getElementById("copied"); | |
shareIcon.addEventListener("click", function() { | |
const id = this.getAttribute("data-id"); | |
const urlToCopy = `${window.location.origin}/?new=false&id=${id}`; | |
navigator.clipboard.writeText(urlToCopy).then(() => { | |
console.log("URL copied to clipboard"); | |
shareIcon.className = "fa-solid fa-check"; | |
//copiedText.style.visibility = "visible"; | |
}).catch(err => { | |
console.log("Could not copy text: ", err); | |
}); | |
}); | |
}); | |
// Connect vs search | |
document.addEventListener("DOMContentLoaded", function() { | |
const urlParams = new URLSearchParams(window.location.search); | |
const countryElement = document.getElementById("country"); | |
if (urlParams.get('new') === 'false') { | |
countryElement.textContent = "connecting..."; | |
} | |
}); | |
// Fullscreen | |
document.addEventListener("DOMContentLoaded", function() { | |
const feed = document.getElementById("feed"); | |
let isFullscreen = false; | |
function toggleFullScreen() { | |
if (!isFullscreen) { | |
if (this.requestFullscreen) { | |
this.requestFullscreen(); | |
} else if (this.mozRequestFullScreen) { | |
this.mozRequestFullScreen(); | |
} else if (this.webkitRequestFullscreen) { | |
this.webkitRequestFullscreen(); | |
} else if (this.msRequestFullscreen) { | |
this.msRequestFullscreen(); | |
} | |
} else { | |
if (document.exitFullscreen) { | |
document.exitFullscreen(); | |
} else if (document.mozCancelFullScreen) { | |
document.mozCancelFullScreen(); | |
} else if (document.webkitExitFullscreen) { | |
document.webkitExitFullscreen(); | |
} else if (document.msExitFullscreen) { | |
document.msExitFullscreen(); | |
} | |
} | |
} | |
feed.addEventListener("click", toggleFullScreen); | |
feed.addEventListener("touchstart", toggleFullScreen); | |
document.addEventListener("fullscreenchange", function() { | |
isFullscreen = !isFullscreen; | |
}); | |
}); | |
// Change feed on space bar press | |
document.addEventListener('keydown', function(event) { | |
if (event.keyCode === 32) { | |
window.location.href = '/?new=true'; | |
} | |
}); | |
// Show more info | |
document.addEventListener('DOMContentLoaded', function() { | |
const infoText = document.getElementById('info-text'); | |
const additionalInfo = document.getElementById('additional-info'); | |
const showMore = document.getElementById('show-more'); | |
const moreButton = document.getElementById('more-button'); | |
// Initial setup | |
additionalInfo.style.height = '0'; | |
additionalInfo.style.overflow = 'hidden'; | |
additionalInfo.style.transition = 'height 0.3s ease-in-out'; | |
showMore.addEventListener('click', function() { | |
if (additionalInfo.style.height === '0px') { | |
const scrollHeight = additionalInfo.scrollHeight; | |
additionalInfo.style.height = `${scrollHeight}px`; | |
showMore.innerHTML = 'less <i style="margin-bottom:20px; color:rgb(53, 53, 53);" id="more-button" class="fa-solid fa-caret-up"></i>'; | |
} else { | |
additionalInfo.style.height = '0'; | |
showMore.innerHTML = 'more <i style="margin-bottom:20px; color:rgb(53, 53, 53);" id="more-button" class="fa-solid fa-caret-down"></i>'; | |
} | |
}); | |
}); | |
</script> | |
</body> | |
</html> |