353 lines
14 KiB
HTML
353 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Route Explorer Pro</title>
|
|
<style>
|
|
body { font-family: sans-serif; background: #1a1a1a; color: #e0e0e0; padding: 15px; line-height: 1.4; }
|
|
.container { max-width: 900px; margin: auto; background: #2a2a2a; padding: 20px; border-radius: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.5); }
|
|
|
|
label { display: block; margin-bottom: 5px; font-weight: bold; color: #4dabf7; font-size: 0.9em; }
|
|
select, input[type="text"] { width: 100%; padding: 12px; margin-bottom: 15px; border-radius: 4px; border: 1px solid #444; background: #333; color: white; box-sizing: border-box; }
|
|
|
|
.checkbox-group { display: flex; gap: 15px; margin-bottom: 15px; }
|
|
.checkbox-container { display: flex; align-items: center; background: #383838; padding: 8px 12px; border-radius: 4px; cursor: pointer; font-size: 0.85em; flex: 1; }
|
|
.checkbox-container input { margin-right: 8px; }
|
|
|
|
.breadcrumb { background: #111; padding: 10px; border-radius: 4px; margin-bottom: 1px; font-family: monospace; font-size: 0.85em; color: #888; border-bottom: 1px solid #333; }
|
|
.breadcrumb span { color: #4dabf7; cursor: pointer; font-weight: bold; }
|
|
|
|
#pathList { max-height: 450px; overflow-y: auto; border: 1px solid #444; background: #222; border-radius: 0 0 4px 4px; }
|
|
.path-row { display: flex; align-items: center; border-bottom: 1px solid #333; }
|
|
.path-row:hover { background: #2d2d2d; }
|
|
|
|
.path-name { flex-grow: 1; padding: 12px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.9em; }
|
|
.btn-target { padding: 12px 18px; cursor: pointer; background: #333; color: #fab005; border: none; border-left: 1px solid #444; font-size: 1.1em; }
|
|
.btn-target:hover { background: #fab005; color: #000; }
|
|
|
|
.is-file { color: #bbb; }
|
|
.is-folder { color: #4dabf7; font-weight: 500; }
|
|
|
|
.output-box { background: #000; border-left: 4px solid #fab005; padding: 15px; margin-top: 15px; word-break: break-all; font-family: monospace; font-size: 0.85em; color: #0f0; }
|
|
.hidden { display: none; }
|
|
|
|
.button-group { display: flex; gap: 10px; margin-top: 10px; }
|
|
.btn-ui { padding: 14px; font-weight: bold; border-radius: 4px; text-decoration: none; text-align: center; flex: 1; color: black; font-family: sans-serif; border: none; font-size: 1em; cursor: pointer;}
|
|
.btn-copy { background: #a5d8ff; }
|
|
.btn-send { background: #fab005; }
|
|
|
|
#intentLinkContainer { margin-top: 15px; text-align: center; padding: 10px; background: #111; border: 1px dashed #444; border-radius: 4px; }
|
|
#intentLink { color: #fab005; font-family: monospace; font-weight: bold; text-decoration: underline; font-size: 1.1em; }
|
|
|
|
.searching-hint { font-size: 0.7em; color: #fab005; float: right; margin-top: -10px; margin-bottom: 5px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="container">
|
|
<label>Route Configuration:</label>
|
|
<select id="routePicker"><option value="">-- Select Device/Route --</option></select>
|
|
|
|
<div id="explorerSection" class="hidden">
|
|
<input type="text" id="searchBar" placeholder="Search... (waits for you to stop typing)">
|
|
<div id="searchHint" class="searching-hint hidden">Typing...</div>
|
|
|
|
<div class="checkbox-group">
|
|
<label class="checkbox-container"><input type="checkbox" id="stripFileToggle" checked> Strip Filename</label>
|
|
<label class="checkbox-container"><input type="checkbox" id="urlEncodeToggle"> Tasker Encode</label>
|
|
</div>
|
|
|
|
<div class="breadcrumb" id="breadcrumb">Root</div>
|
|
<div id="pathList"></div>
|
|
</div>
|
|
|
|
<div id="outputSection" class="hidden">
|
|
<div id="commandOutput" class="output-box"></div>
|
|
<div class="button-group">
|
|
<button class="btn-ui btn-copy" onclick="copyToClipboard()">COPY ADB</button>
|
|
<button id="sendBtn" class="btn-ui btn-send" onclick="handleSendToTasker()">SEND TO TASKER</button>
|
|
</div>
|
|
|
|
<div id="intentLinkContainer" class="hidden">
|
|
<a id="intentLink" href="tasker://IntentReceive">IntentSend</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const ROUTES_FILE = 'routes.txt';
|
|
let routeData = {};
|
|
let masterPathList = [];
|
|
let currentDir = "";
|
|
let searchTimer;
|
|
|
|
async function init() {
|
|
try {
|
|
const res = await fetch(ROUTES_FILE);
|
|
const text = await res.text();
|
|
const lines = text.split('\n').map(l => l.trim()).filter(l => l !== "");
|
|
const picker = document.getElementById('routePicker');
|
|
for (let i = 0; i < lines.length; i += 2) {
|
|
routeData[lines[i]] = lines[i+1];
|
|
picker.add(new Option(lines[i], lines[i]));
|
|
}
|
|
} catch (e) { console.error("Initialization failed"); }
|
|
}
|
|
|
|
document.getElementById('routePicker').onchange = async (e) => {
|
|
if (!e.target.value) return;
|
|
const res = await fetch(`${e.target.value}.txt`);
|
|
const text = await res.text();
|
|
masterPathList = text.split('\n').map(l => l.trim()).filter(l => l !== "");
|
|
currentDir = "";
|
|
document.getElementById('explorerSection').classList.remove('hidden');
|
|
renderExplorer();
|
|
};
|
|
|
|
document.getElementById('searchBar').addEventListener('input', () => {
|
|
const hint = document.getElementById('searchHint');
|
|
hint.classList.remove('hidden');
|
|
|
|
clearTimeout(searchTimer);
|
|
searchTimer = setTimeout(() => {
|
|
hint.classList.add('hidden');
|
|
renderExplorer();
|
|
}, 400);
|
|
});
|
|
|
|
function renderExplorer() {
|
|
const listDiv = document.getElementById('pathList');
|
|
const searchTerm = document.getElementById('searchBar').value.toLowerCase();
|
|
listDiv.innerHTML = '';
|
|
|
|
const bc = document.getElementById('breadcrumb');
|
|
bc.innerHTML = `<span onclick="navigate('')">Root</span> ${currentDir ? ' / ' + currentDir.split('/').map((seg, i, arr) => `<span onclick="navigate('${arr.slice(0,i+1).join('/')}')">${seg}</span>`).join(' / ') : ''}`;
|
|
|
|
let itemsToDisplay = [];
|
|
|
|
if (searchTerm) {
|
|
itemsToDisplay = masterPathList
|
|
.filter(p => p.toLowerCase().includes(searchTerm))
|
|
.slice(0, 200)
|
|
.map(p => ({ path: p, isSearch: true }));
|
|
} else {
|
|
const children = new Set();
|
|
masterPathList.forEach(p => {
|
|
if (currentDir === "") {
|
|
children.add(p.split('/')[0]);
|
|
} else if (p.startsWith(currentDir + '/')) {
|
|
const relative = p.substring(currentDir.length + 1);
|
|
children.add(relative.split('/')[0]);
|
|
}
|
|
});
|
|
itemsToDisplay = Array.from(children).sort().map(name => ({
|
|
path: currentDir ? `${currentDir}/${name}` : name,
|
|
isSearch: false,
|
|
displayName: name
|
|
}));
|
|
}
|
|
|
|
const fragment = document.createDocumentFragment();
|
|
itemsToDisplay.forEach(item => {
|
|
const isFolder = masterPathList.some(p => p.startsWith(item.path + '/'));
|
|
const display = item.isSearch ? item.path : item.displayName;
|
|
|
|
const row = document.createElement('div');
|
|
row.className = 'path-row';
|
|
|
|
const nameSpan = document.createElement('span');
|
|
nameSpan.className = `path-name ${isFolder ? 'is-folder' : 'is-file'}`;
|
|
nameSpan.textContent = (isFolder ? '📁 ' : '📄 ') + display;
|
|
|
|
nameSpan.onclick = () => {
|
|
if (item.isSearch) {
|
|
document.getElementById('searchBar').value = '';
|
|
navigate(isFolder ? item.path : item.path.substring(0, item.path.lastIndexOf('/')));
|
|
} else {
|
|
if (isFolder) navigate(item.path); else selectPath(item.path);
|
|
}
|
|
};
|
|
|
|
const targetBtn = document.createElement('button');
|
|
targetBtn.className = 'btn-target';
|
|
targetBtn.innerHTML = '🎯';
|
|
targetBtn.onclick = (e) => {
|
|
e.stopPropagation();
|
|
selectPath(item.path);
|
|
};
|
|
|
|
row.appendChild(nameSpan);
|
|
row.appendChild(targetBtn);
|
|
fragment.appendChild(row);
|
|
});
|
|
listDiv.appendChild(fragment);
|
|
}
|
|
|
|
function navigate(path) {
|
|
currentDir = path;
|
|
renderExplorer();
|
|
}
|
|
|
|
document.getElementById('stripFileToggle').onchange = () => updateOutput(window.lastPath);
|
|
document.getElementById('urlEncodeToggle').onchange = () => updateOutput(window.lastPath);
|
|
|
|
function selectPath(path) {
|
|
window.lastPath = path;
|
|
updateOutput(path);
|
|
document.getElementById('outputSection').classList.remove('hidden');
|
|
}
|
|
|
|
function updateOutput(path) {
|
|
if (!path) return;
|
|
let p = path;
|
|
|
|
if (document.getElementById('stripFileToggle').checked) {
|
|
if (p.includes('/') && !masterPathList.some(full => full.startsWith(p + '/'))) {
|
|
p = p.substring(0, p.lastIndexOf('/'));
|
|
}
|
|
}
|
|
|
|
const routeName = document.getElementById('routePicker').value;
|
|
const cmd = routeData[routeName].replace('$path', p);
|
|
document.getElementById('commandOutput').textContent = cmd;
|
|
|
|
// Hide the intent link when path changes so it only appears on press
|
|
document.getElementById('intentLinkContainer').classList.add('hidden');
|
|
}
|
|
|
|
async function handleSendToTasker() {
|
|
const cmd = document.getElementById('commandOutput').textContent;
|
|
if (!cmd) return;
|
|
|
|
// 1. Copy text to clipboard
|
|
try {
|
|
await navigator.clipboard.writeText(cmd);
|
|
const btn = document.getElementById('sendBtn');
|
|
const originalText = btn.textContent;
|
|
btn.textContent = "COPIED & SENT!";
|
|
setTimeout(() => btn.textContent = originalText, 1500);
|
|
} catch (err) { console.error('Clip error', err); }
|
|
|
|
// 2. Send text to PHP script
|
|
const phpUrl = `https://alceawis.de/other/extra/scripts/fakesocialmedia/clip.php?clip=${encodeURIComponent(cmd)}`;
|
|
fetch(phpUrl, { mode: 'no-cors' }).catch(e => console.log("PHP Notify Handled"));
|
|
|
|
// 3. Make IntentSend URL appear
|
|
document.getElementById('intentLinkContainer').classList.remove('hidden');
|
|
}
|
|
|
|
function copyToClipboard() {
|
|
navigator.clipboard.writeText(document.getElementById('commandOutput').textContent);
|
|
const btn = document.querySelector('.btn-copy');
|
|
btn.textContent = "COPIED!";
|
|
setTimeout(() => btn.textContent = "COPY ADB", 1500);
|
|
}
|
|
|
|
init();
|
|
</script>
|
|
|
|
|
|
<details><summary>PrerequisiteForSelfHost</summary><pre>
|
|
|
|
|
|
|
|
clip.php
|
|
---------
|
|
<?php
|
|
if (isset($_POST['send'])) {
|
|
$content = $_POST['send'];
|
|
}
|
|
elseif (isset($_GET['clip'])) {
|
|
$content = $_GET['clip'];
|
|
}
|
|
else {
|
|
exit("No content provided.");
|
|
}
|
|
file_put_contents('clip.txt', $content);
|
|
echo "Content saved to 'clip.txt'.";
|
|
exit;
|
|
?>
|
|
<?php
|
|
if (isset($_POST['send'])) {
|
|
$content = $_POST['send'];
|
|
file_put_contents('clip.txt', $content);
|
|
}
|
|
exit;
|
|
?>
|
|
|
|
|
|
IntentReceive.xml.tsk
|
|
---------------------
|
|
<TaskerData sr="" dvi="1" tv="4.9u4m">
|
|
<Task sr="task14">
|
|
<cdate>1767128445686</cdate>
|
|
<edate>1767129026350</edate>
|
|
<id>14</id>
|
|
<nme>IntentReceive</nme>
|
|
<pri>100</pri>
|
|
<Action sr="act0" ve="7">
|
|
<code>123</code>
|
|
<on>false</on>
|
|
<Str sr="arg0" ve="3">sh /sdcard/exec/intentreceive.sh</Str>
|
|
<Int sr="arg1" val="0"/>
|
|
<Int sr="arg2" val="0"/>
|
|
<Str sr="arg3" ve="3"/>
|
|
<Str sr="arg4" ve="3"/>
|
|
<Str sr="arg5" ve="3"/>
|
|
</Action>
|
|
<Action sr="act1" ve="7">
|
|
<code>123</code>
|
|
<Str sr="arg0" ve="3">#!/bin/bash
|
|
|
|
# URL of the script
|
|
SCRIPT_URL="https://alceawis.de/other/extra/scripts/fakesocialmedia/clip.txt"
|
|
|
|
# Fetch the script into a variable
|
|
SCRIPT=$(curl -fsSL "$SCRIPT_URL")
|
|
|
|
# Check if the script was successfully downloaded
|
|
if [ -n "$SCRIPT" ]; then
|
|
echo "Script content (flashed):"
|
|
echo "$SCRIPT" # "Flash" the content directly to the terminal
|
|
|
|
# Execute the command using su -c (with root privileges)
|
|
su -c "$SCRIPT"
|
|
|
|
else
|
|
echo "Failed to download script or script is empty."
|
|
fi</Str>
|
|
<Int sr="arg1" val="0"/>
|
|
<Int sr="arg2" val="0"/>
|
|
<Str sr="arg3" ve="3"/>
|
|
<Str sr="arg4" ve="3"/>
|
|
<Str sr="arg5" ve="3"/>
|
|
</Action>
|
|
</Task>
|
|
</TaskerData>
|
|
|
|
|
|
apk:
|
|
https://m.apkpure.com/tasker-url-launcher/com.aledthomas.taskerurllauncher
|
|
https://alceawis.de/other/extra/scripts/fakesocialmedia/commentload.html?number=80000&text=Oh%20nice%20%0D%0Ahttps%3A%2F%2Fm.apkpure.com%2Ftasker-url-launcher%2Fcom.aled
|
|
|
|
routes.txt
|
|
__________
|
|
|
|
sdcard
|
|
am start -a nextapp.fx.intent.action.OPEN_LOCAL -n nextapp.fx/.ui.ExplorerActivity --es "nextapp.fx.intent.extra.PATH" "$path" -f 0x10000000
|
|
|
|
microsd
|
|
am start -a nextapp.fx.intent.action.OPEN_LOCAL -n nextapp.fx/.ui.ExplorerActivity --es "nextapp.fx.intent.extra.PATH" "/storage/4041-393D/$path" -f 0x10000000
|
|
|
|
alceawis.de
|
|
am start -a nextapp.fx.intent.action.OPEN_NETWORK -n nextapp.fx/.ui.ExplorerActivity --es "nextapp.fx.intent.extra.HOST" "27" --es "nextapp.fx.intent.extra.PATH" "/path" -f 0x10000000
|
|
|
|
m7350
|
|
am start -a nextapp.fx.intent.action.OPEN_NETWORK -n nextapp.fx/.ui.ExplorerActivity --es "nextapp.fx.intent.extra.HOST" "25" --es "nextapp.fx.intent.extra.PATH" "/$path" -f 0x10000000
|
|
|
|
</pre>
|
|
</details>
|
|
</body>
|
|
</html>
|