Completed HashyMagnet; Update Ecoji;
This commit is contained in:
parent
05c2ee7351
commit
0f07037db7
|
@ -50,7 +50,7 @@ Body {
|
||||||
|
|
||||||
#Links > Div {
|
#Links > Div {
|
||||||
Max-Width: Fit-Content;
|
Max-Width: Fit-Content;
|
||||||
Margin: Auto !Important;
|
Margin: Auto;
|
||||||
Padding: 16px;
|
Padding: 16px;
|
||||||
Background-Color: RGBA(16,16,16,0.8);
|
Background-Color: RGBA(16,16,16,0.8);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!--
|
<!--
|
||||||
This is an unaffiliated fork of the Ecoji v1 webapp.
|
This is an unaffiliated fork of the Ecoji v1 webapp.
|
||||||
| Last modified: 2022-09-06.
|
| Last updated: 2022-09-07.
|
||||||
|
|
||||||
Original Ecoji project info:
|
Original Ecoji project info:
|
||||||
| https://github.com/keith-turner/ecoji
|
| https://github.com/keith-turner/ecoji
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
Changes in this Web build (directly edited from the gh-pages branch):
|
Changes in this Web build (directly edited from the gh-pages branch):
|
||||||
| Simplified the CSS,
|
| Simplified the CSS,
|
||||||
| handling decode URIs with "#d=" instead of "?d=",
|
| handling decode URIs with "#d=" instead of "?d=",
|
||||||
| // TODO: autoremove whitespace in decode box,
|
| automatically ignore whitespace in decode box,
|
||||||
| added JavaScript notice,
|
| added JavaScript notice,
|
||||||
| made the app a self-contained AHTML bundle and added notice.
|
| made the app a self-contained AHTML bundle and added notice.
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ Header > Div > * {
|
||||||
Margin-Right: 40px;
|
Margin-Right: 40px;
|
||||||
White-Space: NoWrap;
|
White-Space: NoWrap;
|
||||||
}
|
}
|
||||||
NoScript P {
|
NoScript, NoScript P {
|
||||||
Font-Size: XX-Large;
|
Font-Size: XX-Large;
|
||||||
Padding: 8px;
|
Padding: 8px;
|
||||||
Padding-Bottom: 48px;
|
Padding-Bottom: 48px;
|
||||||
|
@ -581,6 +581,7 @@ function doEncode(){
|
||||||
|
|
||||||
function doDecode(){
|
function doDecode(){
|
||||||
var data = document.getElementById('encoded').value
|
var data = document.getElementById('encoded').value
|
||||||
|
.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "").replaceAll(" ", "")
|
||||||
var decoded = ecojiDecode(data)
|
var decoded = ecojiDecode(data)
|
||||||
document.getElementById('plain').value = decoded
|
document.getElementById('plain').value = decoded
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>HashyMagnet</title>
|
<title>HashyMagnet</title>
|
||||||
<meta name="description" content="Generate Magnet URIs from BitTorrent Hashes!">
|
<meta name="description" content="Generate full BitTorrent Magnet Links from Info Hashes!">
|
||||||
<meta property="og:title" content="HashyMagnet">
|
<meta property="og:title" content="HashyMagnet">
|
||||||
<meta property="og:description" content="Generate Magnet URIs from BitTorrent Hashes!">
|
<meta property="og:description" content="Generate full BitTorrent Magnet Links from Info Hashes!">
|
||||||
<meta property="og:url" content="https://hub.octt.eu.org/HashyMagnet">
|
<meta property="og:url" content="https://hub.octt.eu.org/HashyMagnet">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
@ -21,8 +21,32 @@ Body {
|
||||||
Text-Align: Center;
|
Text-Align: Center;
|
||||||
Font-Family: Sans-Serif;
|
Font-Family: Sans-Serif;
|
||||||
}
|
}
|
||||||
Input, Button {
|
Body:Not(Input, TextArea) {
|
||||||
|
User-Select: None;
|
||||||
|
}
|
||||||
|
|
||||||
|
A {
|
||||||
|
Color: #17C3EA;
|
||||||
|
}
|
||||||
|
A:Active {
|
||||||
|
Color: #0B69BC;
|
||||||
|
}
|
||||||
|
A:Hover {
|
||||||
|
Background: #101060;
|
||||||
|
Color: #E9FFEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NoScript, NoScript P {
|
||||||
|
Font-Size: XX-Large;
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
Height: 2em;
|
Height: 2em;
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
Height: 2.25em;
|
||||||
|
}
|
||||||
|
Input, Button {
|
||||||
Font-Size: Initial;
|
Font-Size: Initial;
|
||||||
}
|
}
|
||||||
Input, TextArea {
|
Input, TextArea {
|
||||||
|
@ -30,7 +54,46 @@ Input, TextArea {
|
||||||
Margin-Top: 8px;
|
Margin-Top: 8px;
|
||||||
Margin-Bottom: 8px;
|
Margin-Bottom: 8px;
|
||||||
}
|
}
|
||||||
|
Input:Disabled, TextArea:Disabled {
|
||||||
|
Color: #000000;
|
||||||
|
Background-Color: #EEEEEE;
|
||||||
|
}
|
||||||
|
Input, TextArea, Button {
|
||||||
|
Color: #000000;
|
||||||
|
Background-Color: #EEFFFF;
|
||||||
|
Border: Solid #808080 1px;
|
||||||
|
Border-Radius: 4px;
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
Color: #202020;
|
||||||
|
Padding-Left: 0.5em;
|
||||||
|
Padding-Right: 0.5em;
|
||||||
|
}
|
||||||
|
Button:Hover {
|
||||||
|
Color: #101010;
|
||||||
|
}
|
||||||
|
Button:Active {
|
||||||
|
Color: #000000;
|
||||||
|
Background-Color: #DDEEEE;
|
||||||
|
}
|
||||||
|
Button:Disabled {
|
||||||
|
Color: #808080;
|
||||||
|
Background-Color: RGBA(16,16,48,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Section {
|
||||||
|
Margin: 4px;
|
||||||
|
}
|
||||||
|
.NoWrap {
|
||||||
|
White-Space: NoWrap;
|
||||||
|
}
|
||||||
|
.LeftAlign {
|
||||||
|
Text-Align: Left;
|
||||||
|
Margin-Left: Calc(5% + 8px);
|
||||||
|
}
|
||||||
|
|
||||||
#Main {
|
#Main {
|
||||||
|
Overflow-X: Hidden;
|
||||||
Overflow-Y: Scroll;
|
Overflow-Y: Scroll;
|
||||||
Max-Height: 100vh;
|
Max-Height: 100vh;
|
||||||
Position: Absolute;
|
Position: Absolute;
|
||||||
|
@ -40,42 +103,90 @@ Input, TextArea {
|
||||||
Right: 0px;
|
Right: 0px;
|
||||||
Z-Index: 4;
|
Z-Index: 4;
|
||||||
}
|
}
|
||||||
.Section {
|
/*
|
||||||
Margin: 4px;
|
#Title, #Title > Div {
|
||||||
|
Max-Width: Fit-Content;
|
||||||
|
Margin: Auto;
|
||||||
}
|
}
|
||||||
.NoWrap {
|
*/
|
||||||
White-Space: NoWrap;
|
|
||||||
|
#ResetBtn {
|
||||||
|
Color: #FF0000;
|
||||||
|
Padding-Bottom: 4px;
|
||||||
|
Width: 2em;
|
||||||
|
}
|
||||||
|
#ResetBtn:Active, #ResetBtn:Hover {
|
||||||
|
Color: #FFFFFF;
|
||||||
|
Background-Color: #FF0000;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="Main">
|
<div id="Main">
|
||||||
<div class="Section">
|
<div id="Title" class="Section"><div>
|
||||||
<h3>HashyMagnet</h3>
|
<div id="TitleTitle">
|
||||||
<p>Generate a full Bit<span style="Color:#AAFFFF;">Torrent</span> Magnet Link from an Info Hash!</p>
|
<h3>HashyMagnet</h3>
|
||||||
|
<p>Generate a full Bit<span style="Color:#AAFFFF;">Torrent</span> Magnet Link from an Info Hash...</p>
|
||||||
|
</div>
|
||||||
<noscript><p>
|
<noscript><p>
|
||||||
This is an actual app, not a badly-made website.
|
This is an actual app, not a badly-made website.
|
||||||
<br>
|
<br>
|
||||||
It needs JavaScript, so you need to enable it.
|
It needs JavaScript to work, so you need to enable it.
|
||||||
<br>
|
<br>
|
||||||
The code is fully open, and you can review it with "View Page Source".
|
The code is fully open, and you can review it with "View Page Source".
|
||||||
</p></noscript>
|
</p></noscript>
|
||||||
</div>
|
<div id="Info">
|
||||||
|
<h4>Info</h4>
|
||||||
|
<p>With this app you can generate full <a href="https://en.m.wikipedia.org/wiki/Magnet_URI_scheme" target="_blank" rel="noopener nofollow">BitTorrent Magnet links</a>, complete with trackers, from a simple Info Hash.</p>
|
||||||
|
<p>You can input your own list of trackers, or you can use the one that's autogenerated by the app from up-to-date lists.</p>
|
||||||
|
<p>Last updated: 2022-09-07.</p>
|
||||||
|
<h4>Special Thanks and Credits</h4>
|
||||||
|
<p>
|
||||||
|
Tracker lists providers:
|
||||||
|
<ul id="ListsProviders">
|
||||||
|
<li><a href="https://github.com/ngosang/trackerslist" target="_blank" rel="noopener nofollow">https://github.com/ngosang/trackerslist</a></li>
|
||||||
|
<li><a href="https://newtrackon.com" target="_blank" rel="noopener nofollow">https://newtrackon.com</a></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Background animations:
|
||||||
|
<br>
|
||||||
|
<a href="https://codinhood.com/micro/animate-octocat-sprite-css" target="_blank" rel="noopener nofollow">https://codinhood.com/micro/animate-octocat-sprite-css</a></p>
|
||||||
|
<h4>License</h4>
|
||||||
|
<pre>HashyMagnet
|
||||||
|
Copyright (C) 2022, OctoSpacc
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <a href="https://www.gnu.org/licenses" target="_blank" rel="noopener nofollow">https://www.gnu.org/licenses</a>.
|
||||||
|
</pre>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
<br>
|
<br>
|
||||||
<div class="Section">
|
<div class="Section">
|
||||||
<div class="NoWrap">
|
<div class="NoWrap">
|
||||||
<button id="ResetBtn">❌</button>
|
<button id="ResetBtn"><big><b>x</b></big></button>
|
||||||
<input id="TextBox" placeholder="📝 Paste Info Hash here...">
|
<input id="TextBox" placeholder="📝 Paste Hash here...">
|
||||||
</div>
|
</div>
|
||||||
<div class="NoWrap">
|
<div class="NoWrap">
|
||||||
<button id="GenerateBtn">Generate Magnet!</button>
|
<button id="GenerateBtn">🧲 Generate Magnet!</button>
|
||||||
<button id="CopyBtn">Copy link</button>
|
<button id="CopyBtn">📋 Copy</button>
|
||||||
<button id="OpenBtn">Open link</button>
|
<button id="OpenBtn">🔗 Open</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="Section">
|
<div class="Section">
|
||||||
<div class="NoWrap">
|
<div class="NoWrap LeftAlign">
|
||||||
<label for="TrackersBtn">Trackers list:</label>
|
<label for="TrackersBtn">Trackers list:</label>
|
||||||
<button id="TrackersBtn"></button>
|
<button id="TrackersBtn"></button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,38 +197,50 @@ Input, TextArea {
|
||||||
<div class="ocean"><div class="bubble bubble-1"></div><div class="bubble bubble-2"></div><div class="bubble bubble-3"></div><div class="bubble bubble-4"></div><div class="bubble bubble-5"></div><div class="bubble bubble-6"></div><div class="bubble bubble-7"></div><div class="bubble bubble-8"></div><div class="bubble bubble-9"></div><div class="bubble bubble-10"></div><div class="bubble bubble-11"></div></div>
|
<div class="ocean"><div class="bubble bubble-1"></div><div class="bubble bubble-2"></div><div class="bubble bubble-3"></div><div class="bubble bubble-4"></div><div class="bubble bubble-5"></div><div class="bubble bubble-6"></div><div class="bubble bubble-7"></div><div class="bubble bubble-8"></div><div class="bubble bubble-9"></div><div class="bubble bubble-10"></div><div class="bubble bubble-11"></div></div>
|
||||||
<script>
|
<script>
|
||||||
var Generated = false;
|
var Generated = false;
|
||||||
var Trackers = [];
|
var Trackers = [],
|
||||||
var TrackersNum = 35;
|
FetchTrackers = [];
|
||||||
|
var MaxFetchTrackers = 40;
|
||||||
const TrackersSources = [
|
const TrackersSources = [
|
||||||
"https://ngosang.github.io/trackerslist/trackers_best.txt",
|
"https://ngosang.github.io/trackerslist/trackers_best.txt",
|
||||||
"https://newtrackon.com/api/stable",
|
"https://newtrackon.com/api/stable",
|
||||||
];
|
];
|
||||||
|
|
||||||
async function FetchTrackers() {
|
function SplitLines(Text) {
|
||||||
|
if (Text == "") {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
return Text.trim().replaceAll("\r","").replace(/\n\s*\n/g,"\n").split("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function DoFetchTrackers() {
|
||||||
for (let i = 0; i < TrackersSources.length; i++) {
|
for (let i = 0; i < TrackersSources.length; i++) {
|
||||||
let Req = await fetch(TrackersSources[i]);
|
let Req = await fetch(TrackersSources[i]);
|
||||||
let Data = await Req.text();
|
let Data = await Req.text();
|
||||||
Trackers = Trackers.concat(Data.replaceAll("\n\n","\n").split("\n"));
|
FetchTrackers = FetchTrackers.concat(SplitLines(Data));
|
||||||
}
|
}
|
||||||
Trackers = Trackers.slice(0,TrackersNum);
|
FetchTrackers = FetchTrackers.slice(0,MaxFetchTrackers);
|
||||||
}
|
}
|
||||||
|
|
||||||
function WriteTrackers() {
|
function WriteFetchTrackers() {
|
||||||
for (let i = 0; i < Trackers.length; i++) {
|
for (let i = 0; i < FetchTrackers.length; i++) {
|
||||||
TrackersArea.value += Trackers[i] + "\n\n";
|
TrackersArea.value += FetchTrackers[i] + "\n\n";
|
||||||
}
|
}
|
||||||
|
StoreTrackers();
|
||||||
DoRedraw();
|
DoRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
function StoreTrackers() {
|
function StoreTrackers() {
|
||||||
|
Trackers = SplitLines(TrackersArea.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function FetchWriteTrackers() {
|
async function CallWriteFetchTrackers() {
|
||||||
await FetchTrackers();
|
await DoFetchTrackers();
|
||||||
WriteTrackers();
|
WriteFetchTrackers();
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateBtn.onclick = function() {
|
GenerateBtn.onclick = function() {
|
||||||
|
TextBox.value = TextBox.value.substr(TextBox.value.lastIndexOf(":")+1);
|
||||||
TextBox.value = "magnet:?xt=urn:btih:" + TextBox.value;
|
TextBox.value = "magnet:?xt=urn:btih:" + TextBox.value;
|
||||||
for (let i = 0; i < Trackers.length; i++) {
|
for (let i = 0; i < Trackers.length; i++) {
|
||||||
TextBox.value += "&tr=" + encodeURIComponent(Trackers[i]);
|
TextBox.value += "&tr=" + encodeURIComponent(Trackers[i]);
|
||||||
|
@ -127,21 +250,31 @@ GenerateBtn.onclick = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
function DoRedraw() {
|
function DoRedraw() {
|
||||||
|
TextBox.style = "";
|
||||||
|
let TextBoxWidth = TextBox.offsetWidth;
|
||||||
if (Generated) {
|
if (Generated) {
|
||||||
|
TextBox.disabled = true;
|
||||||
|
GenerateBtn.disabled = true;
|
||||||
GenerateBtn.hidden = true;
|
GenerateBtn.hidden = true;
|
||||||
ResetBtn.hidden = false;
|
ResetBtn.hidden = false;
|
||||||
|
TextBox.style = "Width:" + (TextBoxWidth - ResetBtn.offsetWidth - 12) + "px;"
|
||||||
CopyBtn.hidden = false;
|
CopyBtn.hidden = false;
|
||||||
OpenBtn.hidden = false;
|
OpenBtn.hidden = false;
|
||||||
} else {
|
} else {
|
||||||
|
TextBox.disabled = false;
|
||||||
|
GenerateBtn.disabled = false;
|
||||||
GenerateBtn.hidden = false;
|
GenerateBtn.hidden = false;
|
||||||
ResetBtn.hidden = true;
|
ResetBtn.hidden = true;
|
||||||
|
|
||||||
CopyBtn.hidden = true;
|
CopyBtn.hidden = true;
|
||||||
OpenBtn.hidden = true;
|
OpenBtn.hidden = true;
|
||||||
}
|
}
|
||||||
|
if (TextBox.value) {
|
||||||
|
GenerateBtn.disabled = false;
|
||||||
|
} else {
|
||||||
|
GenerateBtn.disabled = true;
|
||||||
|
}
|
||||||
if (TrackersArea.value) {
|
if (TrackersArea.value) {
|
||||||
TrackersBtn.textContent = "🧹 Clear";
|
TrackersBtn.textContent = "🗑️ Clear";
|
||||||
} else {
|
} else {
|
||||||
TrackersBtn.textContent = "🔄 Refresh";
|
TrackersBtn.textContent = "🔄 Refresh";
|
||||||
}
|
}
|
||||||
|
@ -164,17 +297,39 @@ OpenBtn.onclick = function() {
|
||||||
TrackersBtn.onclick = function() {
|
TrackersBtn.onclick = function() {
|
||||||
if (TrackersArea.value) {
|
if (TrackersArea.value) {
|
||||||
TrackersArea.value = "";
|
TrackersArea.value = "";
|
||||||
|
StoreTrackers();
|
||||||
} else {
|
} else {
|
||||||
WriteTrackers();
|
WriteFetchTrackers();
|
||||||
}
|
}
|
||||||
DoRedraw();
|
DoRedraw();
|
||||||
};
|
};
|
||||||
|
|
||||||
TrackersArea.onchange = StoreTrackers;
|
function TrackersAreaOnChange() {
|
||||||
|
StoreTrackers();
|
||||||
|
DoRedraw();
|
||||||
|
}
|
||||||
|
TrackersArea.onchange = TrackersAreaOnChange;
|
||||||
|
TrackersArea.oninput = TrackersAreaOnChange;
|
||||||
|
TrackersArea.onpaste = TrackersAreaOnChange;
|
||||||
|
|
||||||
|
TextBox.onkeydown = function(e) {
|
||||||
|
if (e.keyCode == 13 && !Generated) {
|
||||||
|
GenerateBtn.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
TextBox.onchange = DoRedraw;
|
||||||
|
TextBox.oninput = DoRedraw;
|
||||||
|
TextBox.onpaste = DoRedraw;
|
||||||
|
|
||||||
|
window.onresize = DoRedraw;
|
||||||
|
|
||||||
|
Info.hidden = true;
|
||||||
|
TitleTitle.onclick = function() {
|
||||||
|
Info.hidden = !Info.hidden;
|
||||||
|
};
|
||||||
|
|
||||||
DoRedraw();
|
DoRedraw();
|
||||||
FetchWriteTrackers();
|
CallWriteFetchTrackers();
|
||||||
TrackersBtn.hidden = true;
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue