@officebeats/matrix-iptv-cli 3.4.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.html +120 -2
- package/package.json +1 -1
- package/scripts/check_host.py +49 -0
- package/scripts/install-binary.js +13 -4
- package/test_bounds_debug.exe +0 -0
- package/test_bounds_debug.pdb +0 -0
- package/test_bounds_debug.rs +34 -0
package/index.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
@@ -25,18 +25,60 @@
|
|
|
25
25
|
line-height: 1.1;
|
|
26
26
|
overflow: hidden;
|
|
27
27
|
border-bottom: 1px solid #003b00;
|
|
28
|
+
touch-action: none; /* Prevent browser scrolling to allow custom touch gestures */
|
|
28
29
|
}
|
|
29
30
|
#video-container {
|
|
30
31
|
width: 100%;
|
|
31
32
|
background: #000;
|
|
32
33
|
display: none;
|
|
33
|
-
position: relative;
|
|
34
|
+
position: relative; /* ensure overlay positioning works */
|
|
34
35
|
aspect-ratio: 16 / 9;
|
|
35
36
|
border-top: 2px solid #00ff41;
|
|
37
|
+
box-shadow: 0 0 20px rgba(0, 255, 65, 0.4);
|
|
36
38
|
}
|
|
37
39
|
video {
|
|
38
40
|
width: 100%;
|
|
39
41
|
height: 100%;
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
44
|
+
#video-close {
|
|
45
|
+
position: absolute;
|
|
46
|
+
top: 10px;
|
|
47
|
+
right: 10px;
|
|
48
|
+
background: rgba(13, 2, 8, 0.8);
|
|
49
|
+
color: #00ff41;
|
|
50
|
+
border: 1px solid #00ff41;
|
|
51
|
+
padding: 8px 12px;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
z-index: 10;
|
|
54
|
+
font-weight: bold;
|
|
55
|
+
font-family: inherit;
|
|
56
|
+
backdrop-filter: blur(4px);
|
|
57
|
+
transition: all 0.2s ease;
|
|
58
|
+
}
|
|
59
|
+
#video-close:hover {
|
|
60
|
+
background: #00ff41;
|
|
61
|
+
color: #0d0208;
|
|
62
|
+
box-shadow: 0 0 10px #00ff41;
|
|
63
|
+
}
|
|
64
|
+
.mobile-controls {
|
|
65
|
+
display: none;
|
|
66
|
+
position: absolute;
|
|
67
|
+
bottom: 20px;
|
|
68
|
+
left: 0;
|
|
69
|
+
width: 100%;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
gap: 10px;
|
|
72
|
+
z-index: 10;
|
|
73
|
+
opacity: 0.7;
|
|
74
|
+
}
|
|
75
|
+
.ctrl-btn {
|
|
76
|
+
background: rgba(13, 2, 8, 0.8);
|
|
77
|
+
border: 1px solid #00ff41;
|
|
78
|
+
color: #00ff41;
|
|
79
|
+
padding: 10px 15px;
|
|
80
|
+
font-weight: bold;
|
|
81
|
+
border-radius: 5px;
|
|
40
82
|
}
|
|
41
83
|
@media (min-width: 1024px) {
|
|
42
84
|
#terminal {
|
|
@@ -49,13 +91,33 @@
|
|
|
49
91
|
right: 20px;
|
|
50
92
|
width: 480px;
|
|
51
93
|
border: 2px solid #00ff41;
|
|
94
|
+
box-shadow: 0 0 15px rgba(0, 255, 65, 0.5);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
@media (max-width: 1023px) {
|
|
98
|
+
.mobile-controls {
|
|
99
|
+
display: flex;
|
|
52
100
|
}
|
|
53
101
|
}
|
|
54
102
|
</style>
|
|
55
103
|
</head>
|
|
56
104
|
<body>
|
|
57
105
|
<div id="terminal">Loading Matrix Interface...</div>
|
|
106
|
+
<div class="mobile-controls">
|
|
107
|
+
<!-- Added explicit back button for easy exit on mobile without gestures -->
|
|
108
|
+
<button
|
|
109
|
+
class="ctrl-btn"
|
|
110
|
+
onclick="
|
|
111
|
+
document.dispatchEvent(
|
|
112
|
+
new KeyboardEvent('keydown', { key: 'Escape' }),
|
|
113
|
+
)
|
|
114
|
+
"
|
|
115
|
+
>
|
|
116
|
+
ESC / BACK
|
|
117
|
+
</button>
|
|
118
|
+
</div>
|
|
58
119
|
<div id="video-container">
|
|
120
|
+
<button id="video-close" onclick="closeVideo()">[ X ] CLOSE</button>
|
|
59
121
|
<video id="video" controls playsinline></video>
|
|
60
122
|
</div>
|
|
61
123
|
|
|
@@ -82,6 +144,13 @@
|
|
|
82
144
|
});
|
|
83
145
|
}
|
|
84
146
|
};
|
|
147
|
+
|
|
148
|
+
window.closeVideo = function () {
|
|
149
|
+
const video = document.getElementById("video");
|
|
150
|
+
video.pause();
|
|
151
|
+
video.src = "";
|
|
152
|
+
document.getElementById("video-container").style.display = "none";
|
|
153
|
+
};
|
|
85
154
|
</script>
|
|
86
155
|
|
|
87
156
|
<script type="module">
|
|
@@ -116,6 +185,55 @@
|
|
|
116
185
|
}
|
|
117
186
|
client.handle_key(event.key);
|
|
118
187
|
});
|
|
188
|
+
|
|
189
|
+
// Touch Input Handling Setup
|
|
190
|
+
let touchStartX = 0;
|
|
191
|
+
let touchStartY = 0;
|
|
192
|
+
let touchStartT = 0;
|
|
193
|
+
|
|
194
|
+
document.addEventListener(
|
|
195
|
+
"touchstart",
|
|
196
|
+
(e) => {
|
|
197
|
+
if (
|
|
198
|
+
e.target.tagName.toLowerCase() === "button" ||
|
|
199
|
+
e.target.tagName.toLowerCase() === "video"
|
|
200
|
+
)
|
|
201
|
+
return;
|
|
202
|
+
touchStartX = e.changedTouches[0].screenX;
|
|
203
|
+
touchStartY = e.changedTouches[0].screenY;
|
|
204
|
+
touchStartT = Date.now();
|
|
205
|
+
},
|
|
206
|
+
{ passive: false },
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
document.addEventListener("touchend", (e) => {
|
|
210
|
+
if (
|
|
211
|
+
e.target.tagName.toLowerCase() === "button" ||
|
|
212
|
+
e.target.tagName.toLowerCase() === "video"
|
|
213
|
+
)
|
|
214
|
+
return;
|
|
215
|
+
let touchEndX = e.changedTouches[0].screenX;
|
|
216
|
+
let touchEndY = e.changedTouches[0].screenY;
|
|
217
|
+
let dx = touchEndX - touchStartX;
|
|
218
|
+
let dy = touchEndY - touchStartY;
|
|
219
|
+
let dt = Date.now() - touchStartT;
|
|
220
|
+
|
|
221
|
+
if (dt < 400) {
|
|
222
|
+
// Tap or quick swipe
|
|
223
|
+
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 30) {
|
|
224
|
+
// Horizontal Swipe
|
|
225
|
+
if (dx > 0) client.handle_key("ArrowRight");
|
|
226
|
+
else client.handle_key("ArrowLeft");
|
|
227
|
+
} else if (Math.abs(dy) > Math.abs(dx) && Math.abs(dy) > 30) {
|
|
228
|
+
// Vertical Swipe
|
|
229
|
+
if (dy > 0) client.handle_key("ArrowDown");
|
|
230
|
+
else client.handle_key("ArrowUp");
|
|
231
|
+
} else if (Math.abs(dx) < 10 && Math.abs(dy) < 10) {
|
|
232
|
+
// Tap
|
|
233
|
+
client.handle_key("Enter");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
119
237
|
} catch (e) {
|
|
120
238
|
console.error("Wasm Init Failed:", e);
|
|
121
239
|
document.getElementById("terminal").textContent =
|
package/package.json
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
host = "zfruvync.duperab.xyz"
|
|
5
|
+
print(f"Checking host: {host}")
|
|
6
|
+
|
|
7
|
+
# 1. System DNS
|
|
8
|
+
try:
|
|
9
|
+
ip = socket.gethostbyname(host)
|
|
10
|
+
print(f"[System DNS] Resolved to: {ip}")
|
|
11
|
+
except Exception as e:
|
|
12
|
+
print(f"[System DNS] Failed: {e}")
|
|
13
|
+
|
|
14
|
+
# 2. Google DoH
|
|
15
|
+
try:
|
|
16
|
+
resp = requests.get(f"https://dns.google/resolve?name={host}", timeout=10)
|
|
17
|
+
data = resp.json()
|
|
18
|
+
if data.get("Status") == 0:
|
|
19
|
+
ips = [ans["data"] for ans in data.get("Answer", []) if ans["type"] == 1]
|
|
20
|
+
print(f"[Google DoH] Resolved to: {ips}")
|
|
21
|
+
else:
|
|
22
|
+
print(f"[Google DoH] Failed with status {data.get('Status')}")
|
|
23
|
+
except Exception as e:
|
|
24
|
+
print(f"[Google DoH] Error: {e}")
|
|
25
|
+
|
|
26
|
+
# 3. Cloudflare DoH
|
|
27
|
+
try:
|
|
28
|
+
resp = requests.get(f"https://cloudflare-dns.com/dns-query?name={host}", headers={"Accept": "application/dns-json"}, timeout=10)
|
|
29
|
+
data = resp.json()
|
|
30
|
+
if data.get("Status") == 0:
|
|
31
|
+
ips = [ans["data"] for ans in data.get("Answer", []) if ans["type"] == 1]
|
|
32
|
+
print(f"[Cloudflare DoH] Resolved to: {ips}")
|
|
33
|
+
else:
|
|
34
|
+
print(f"[Cloudflare DoH] Failed with status {data.get('Status')}")
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(f"[Cloudflare DoH] Error: {e}")
|
|
37
|
+
|
|
38
|
+
# 4. Quad9 DoH
|
|
39
|
+
try:
|
|
40
|
+
# Quad9 has a JSON API at https://dns.quad9.net/resolve?name=
|
|
41
|
+
resp = requests.get(f"https://dns.quad9.net/resolve?name={host}", timeout=10)
|
|
42
|
+
data = resp.json()
|
|
43
|
+
if data.get("Status") == 0:
|
|
44
|
+
ips = [ans["data"] for ans in data.get("Answer", []) if ans["type"] == 1]
|
|
45
|
+
print(f"[Quad9 DoH] Resolved to: {ips}")
|
|
46
|
+
else:
|
|
47
|
+
print(f"[Quad9 DoH] Failed with status {data.get('Status')}")
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"[Quad9 DoH] Error: {e}")
|
|
@@ -39,26 +39,35 @@ if (!fs.existsSync(binDir)) {
|
|
|
39
39
|
|
|
40
40
|
function download(url, dest) {
|
|
41
41
|
return new Promise((resolve, reject) => {
|
|
42
|
-
const file = fs.createWriteStream(dest);
|
|
43
42
|
https
|
|
44
43
|
.get(url, (response) => {
|
|
45
|
-
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
46
|
-
// Handle Redirect
|
|
44
|
+
if (response.statusCode === 302 || response.statusCode === 301 || response.statusCode === 307 || response.statusCode === 308) {
|
|
45
|
+
// Handle Redirect without leaving locks open
|
|
47
46
|
download(response.headers.location, dest).then(resolve).catch(reject);
|
|
48
47
|
return;
|
|
49
48
|
}
|
|
49
|
+
|
|
50
50
|
if (response.statusCode !== 200) {
|
|
51
51
|
reject(new Error(`Failed to download: ${response.statusCode}`));
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
// Only open the file stream if the download actually works
|
|
56
|
+
const file = fs.createWriteStream(dest);
|
|
54
57
|
response.pipe(file);
|
|
58
|
+
|
|
55
59
|
file.on("finish", () => {
|
|
56
60
|
file.close();
|
|
57
61
|
resolve();
|
|
58
62
|
});
|
|
63
|
+
|
|
64
|
+
file.on("error", (err) => {
|
|
65
|
+
file.close();
|
|
66
|
+
fs.unlink(dest, () => {});
|
|
67
|
+
reject(err);
|
|
68
|
+
});
|
|
59
69
|
})
|
|
60
70
|
.on("error", (err) => {
|
|
61
|
-
fs.unlink(dest, () => {});
|
|
62
71
|
reject(err);
|
|
63
72
|
});
|
|
64
73
|
});
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
fn main() {
|
|
2
|
+
let mock_name = "US | MSNBC HEVC";
|
|
3
|
+
|
|
4
|
+
// Stream layout extraction natively replicated to simulate Wave Terminal bugs
|
|
5
|
+
let mut spans = vec![];
|
|
6
|
+
let row_num = format!("{:>4} ", 1);
|
|
7
|
+
spans.push(row_num);
|
|
8
|
+
spans.push(" ".to_string()); // Used to be `│ `
|
|
9
|
+
|
|
10
|
+
let c = format!("{:<30} ", "MSNBC HEVC");
|
|
11
|
+
spans.push(c);
|
|
12
|
+
|
|
13
|
+
println!("DEBUG: Stream constraint outputs - ");
|
|
14
|
+
for span in spans {
|
|
15
|
+
println!("--> '{}' (len {})", span, span.len());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Category Grid constraints
|
|
19
|
+
println!("\nDEBUG: Category 4-column output simulation - ");
|
|
20
|
+
let max_name_len: usize = 20;
|
|
21
|
+
let count: usize = 1205;
|
|
22
|
+
let count_str = format!("{:04}", count); // Used to be `[{:04}]`
|
|
23
|
+
|
|
24
|
+
let pre_pad = " "; // active
|
|
25
|
+
let fav_marker = " ";
|
|
26
|
+
let cat_icon = "🎬 "; // 3 bytes, 2 chars visual? Unicode width handling is likely what breaks Wave
|
|
27
|
+
let name_clean = format!("{}{}{} {}", pre_pad, fav_marker, cat_icon, "MOVIES");
|
|
28
|
+
|
|
29
|
+
let padded_name = format!("{:<max_name_len$}", name_clean, max_name_len=max_name_len);
|
|
30
|
+
println!("--> '{}' (len {} chars, {} bytes)", padded_name, padded_name.chars().count(), padded_name.len());
|
|
31
|
+
println!("--> '{}' (len {})", count_str, count_str.len());
|
|
32
|
+
println!("--> GAP: '{}' (len {})", "", "".len()); // Changed padding space to empty constraint
|
|
33
|
+
}
|
|
34
|
+
|