mirror of
https://github.com/zyqunix/tools.git
synced 2025-07-05 22:10:31 +02:00
morse code and ip lookup
This commit is contained in:
parent
82bbc6c0cd
commit
9ed3ee790e
8 changed files with 388 additions and 5 deletions
15
global.css
15
global.css
|
@ -37,7 +37,14 @@ a:hover, svg:hover {
|
||||||
color: #c099ff;
|
color: #c099ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
.card {
|
||||||
background-color: #c099ff;
|
background-color: #252525;
|
||||||
color: #2a2a2a;
|
padding: 20px;
|
||||||
}
|
border-radius: 10px;
|
||||||
|
width: 600px !important;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow {
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
21
ip/index.html
Normal file
21
ip/index.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>IP Lookup</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<link rel="shortcut icon" href="https://rimgo.pussthecat.org/RFbdMMB.png" type="image/x-icon">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>IP Lookup</h1>
|
||||||
|
<div class="card shadow">
|
||||||
|
<input type="text" id="ipInput" placeholder="Enter IP address">
|
||||||
|
<button id="lookupElem">Lookup</button>
|
||||||
|
<div class="your tooltip" data-tooltip="Only provides IPv6.">Your IP: <span id="your-ip">69.420.69.69</span></div>
|
||||||
|
</div>
|
||||||
|
<div id="output"></div>
|
||||||
|
|
||||||
|
<script src="index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
48
ip/index.js
Normal file
48
ip/index.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
const lookupElem = document.getElementById('lookupElem');
|
||||||
|
const yourIp = document.getElementById('your-ip');
|
||||||
|
|
||||||
|
function getFlagEmoji(countryCode) {
|
||||||
|
return countryCode
|
||||||
|
.toUpperCase()
|
||||||
|
.replace(/./g, char => String.fromCodePoint(127397 + char.charCodeAt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchIp() {
|
||||||
|
const ip = document.getElementById("ipInput").value;
|
||||||
|
fetch(`https://ipapi.co/${ip}/json/`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const flag = getFlagEmoji(data.country_code || '');
|
||||||
|
const table = `
|
||||||
|
<table>
|
||||||
|
<tr><th>IP</th><td>${data.ip}</td></tr>
|
||||||
|
<tr><th>City</th><td>${data.city}</td></tr>
|
||||||
|
<tr><th>Postal Code</th><td>${data.postal}</td></tr>
|
||||||
|
<tr><th>Region</th><td>${data.region}</td></tr>
|
||||||
|
<tr><th>Country</th><td>${flag} ${data.country_name} (${data.country_code})</td></tr>
|
||||||
|
<tr><th>Timezone</th><td>${data.timezone}</td></tr>
|
||||||
|
<tr><th>Organization</th><td>${data.org}</td></tr>
|
||||||
|
<tr><th>Coordinates</th><td>${data.latitude}, ${data.longitude}</td></tr>
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
document.getElementById("output").innerHTML = table;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
document.getElementById("output").textContent = "Error: " + err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getYour() {
|
||||||
|
fetch(`https://ipapi.co/json/?ip=ipv4`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
yourIp.innerHTML = data.ip;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
yourIp.textContent = "Error: " + err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', getYour);
|
||||||
|
|
||||||
|
lookupElem.addEventListener('click', fetchIp);
|
104
ip/style.css
Normal file
104
ip/style.css
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
@import url(/global.css);
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
background: #1e1e1e;
|
||||||
|
border: 1px solid #444;
|
||||||
|
color: #f0f0f0;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 70%;
|
||||||
|
margin-right: 10px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
outline: none;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: #c099ff;
|
||||||
|
color: #1e1e1e;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 20px;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #a875ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output {
|
||||||
|
margin-top: 25px;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 640px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px 14px;
|
||||||
|
border: 2px solid #2a2a2a;
|
||||||
|
background-color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
th:hover,
|
||||||
|
td:hover {
|
||||||
|
background-color: #232323;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.your {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#your-ip:not(:hover) {
|
||||||
|
filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip::after {
|
||||||
|
content: attr(data-tooltip);
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
bottom: 125%;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border: 2px solid rgba(150, 150, 150, 0.1);
|
||||||
|
color: #fff;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.3s, visibility 0.3s;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:hover::after {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
25
morse/index.html
Normal file
25
morse/index.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Morse Translator</title>
|
||||||
|
<link rel="shortcut icon" href="https://rimgo.pussthecat.org/RFbdMMB.png" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card shadow">
|
||||||
|
<h1>Morse Translator</h1>
|
||||||
|
<textarea id="textInput" placeholder="Enter text..." rows="5"></textarea>
|
||||||
|
<button id="translate-to-morse">Translate to Morse</button>
|
||||||
|
<textarea id="morseOutput" placeholder="Morse Code..." rows="5"></textarea>
|
||||||
|
<button id="translate-to-text">Translate to Text</button>
|
||||||
|
<span>
|
||||||
|
<button id="play-sound">Play Sound</button>
|
||||||
|
<button id="export">Export Morse</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
146
morse/index.js
Normal file
146
morse/index.js
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
const morseElem = document.getElementById('translate-to-morse');
|
||||||
|
const textElem = document.getElementById('translate-to-text');
|
||||||
|
const soundElem = document.getElementById('play-sound');
|
||||||
|
const exportElem = document.getElementById('export');
|
||||||
|
|
||||||
|
const morseCode = {
|
||||||
|
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', '0': '-----', ' ': '/'
|
||||||
|
};
|
||||||
|
|
||||||
|
const morseToText = Object.fromEntries(Object.entries(morseCode).map(([key, value]) => [value, key]));
|
||||||
|
|
||||||
|
function translateToMorse() {
|
||||||
|
const text = document.getElementById('textInput').value.toUpperCase();
|
||||||
|
const morse = text.split('').map(char => morseCode[char] || '').join(' ');
|
||||||
|
document.getElementById('morseOutput').value = morse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateToText() {
|
||||||
|
const morse = document.getElementById('morseOutput').value.trim();
|
||||||
|
const text = morse.split(' ').map(code => morseToText[code] || '').join('');
|
||||||
|
document.getElementById('textInput').value = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function playMorseSound() {
|
||||||
|
const morse = document.getElementById('morseOutput').value.trim();
|
||||||
|
let audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
let dotDuration = 200;
|
||||||
|
let dashDuration = dotDuration * 3;
|
||||||
|
let gapDuration = dotDuration;
|
||||||
|
|
||||||
|
function playTone(freq, duration, volume) {
|
||||||
|
const oscillator = audioContext.createOscillator();
|
||||||
|
const gainNode = audioContext.createGain();
|
||||||
|
oscillator.connect(gainNode);
|
||||||
|
gainNode.connect(audioContext.destination);
|
||||||
|
oscillator.type = 'sine';
|
||||||
|
oscillator.frequency.setValueAtTime(freq, audioContext.currentTime);
|
||||||
|
gainNode.gain.setValueAtTime(volume, audioContext.currentTime);
|
||||||
|
oscillator.start();
|
||||||
|
oscillator.stop(audioContext.currentTime + duration / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
let position = 0;
|
||||||
|
function playMorseCode() {
|
||||||
|
if (position < morse.length) {
|
||||||
|
const symbol = morse[position];
|
||||||
|
|
||||||
|
if (symbol === '.') {
|
||||||
|
playTone(1000, dotDuration, 0.1);
|
||||||
|
position++;
|
||||||
|
setTimeout(playMorseCode, dotDuration + gapDuration);
|
||||||
|
} else if (symbol === '-') {
|
||||||
|
playTone(1000, dashDuration, 0.1);
|
||||||
|
position++;
|
||||||
|
setTimeout(playMorseCode, dashDuration + gapDuration);
|
||||||
|
} else if (symbol === ' ') {
|
||||||
|
position++;
|
||||||
|
setTimeout(playMorseCode, gapDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playMorseCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportSound() {
|
||||||
|
const morse = document.getElementById('morseOutput').value.trim();
|
||||||
|
let dotDuration = 200;
|
||||||
|
let dashDuration = dotDuration * 3;
|
||||||
|
let gapDuration = dotDuration;
|
||||||
|
|
||||||
|
let sampleRate = 44100;
|
||||||
|
let samples = [];
|
||||||
|
|
||||||
|
function addSilence(duration) {
|
||||||
|
let count = (sampleRate * duration) / 1000;
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
samples.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTone(freq, duration) {
|
||||||
|
let count = (sampleRate * duration) / 1000;
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
let t = i / sampleRate;
|
||||||
|
samples.push(Math.sin(2 * Math.PI * freq * t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let symbol of morse) {
|
||||||
|
if (symbol === '.') {
|
||||||
|
addTone(1000, dotDuration);
|
||||||
|
addSilence(gapDuration);
|
||||||
|
} else if (symbol === '-') {
|
||||||
|
addTone(1000, dashDuration);
|
||||||
|
addSilence(gapDuration);
|
||||||
|
} else if (symbol === ' ') {
|
||||||
|
addSilence(gapDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = new ArrayBuffer(44 + samples.length * 2);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
|
||||||
|
function writeString(offset, string) {
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
view.setUint8(offset + i, string.charCodeAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// i have no idea what this shit is or how it works, but it does :rofl:
|
||||||
|
writeString(0, 'RIFF');
|
||||||
|
view.setUint32(4, 36 + samples.length * 2, true);
|
||||||
|
writeString(8, 'WAVE');
|
||||||
|
writeString(12, 'fmt ');
|
||||||
|
view.setUint32(16, 16, true);
|
||||||
|
view.setUint16(20, 1, true);
|
||||||
|
view.setUint16(22, 1, true);
|
||||||
|
view.setUint32(24, sampleRate, true);
|
||||||
|
view.setUint32(28, sampleRate * 2, true);
|
||||||
|
view.setUint16(32, 2, true);
|
||||||
|
view.setUint16(34, 16, true);
|
||||||
|
writeString(36, 'data');
|
||||||
|
view.setUint32(40, samples.length * 2, true);
|
||||||
|
|
||||||
|
for (let i = 0; i < samples.length; i++) {
|
||||||
|
let s = Math.max(-1, Math.min(1, samples[i]));
|
||||||
|
view.setInt16(44 + i * 2, s * 32767, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([view], { type: 'audio/wav' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'morse-code.wav';
|
||||||
|
a.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
morseElem.addEventListener('click', translateToMorse);
|
||||||
|
|
||||||
|
textElem.addEventListener('click', translateToText);
|
||||||
|
|
||||||
|
soundElem.addEventListener('click', playMorseSound);
|
||||||
|
|
||||||
|
exportElem.addEventListener('click', exportSound);
|
33
morse/style.css
Normal file
33
morse/style.css
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
@import url(/global.css);
|
||||||
|
|
||||||
|
.container {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 20px;
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea, input, button {
|
||||||
|
width: 70%;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: none;
|
||||||
|
background-color: #333;
|
||||||
|
color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: none;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
|
@ -184,7 +184,6 @@ div[class="name-percent-container"] > img.image {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
cursor: help;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue