-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathindex.html
More file actions
289 lines (246 loc) · 16.1 KB
/
Copy pathindex.html
File metadata and controls
289 lines (246 loc) · 16.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>AltDirect</title>
<meta name="description" content="AltStore sources, simplified.">
<meta name="keywords" content="AltDirect, AltStore sources, AltStore, iOS sideloading, app sources">
<meta name="author" content="AltDirect">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://stikstore.app/altdirect/">
<meta property="og:title" content="AltDirect">
<meta property="og:description" content="AltStore sources, simplified.">
<meta property="og:image" content="https://stikstore.app/altdirect/assets/png/Logo_Blue.png">
<meta property="og:url" content="https://stikstore.app/altdirect/">
<meta property="og:type" content="website">
<meta property="og:locale" content="en_US">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="AltDirect">
<meta name="twitter:description" content="AltStore sources, simplified.">
<meta name="twitter:image" content="https://stikstore.app/altdirect/assets/png/Logo_Blue.png">
<meta name="twitter:site" content="@AltDirect">
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#f5f5f7" media="(prefers-color-scheme: light)">
<link rel="icon" href="assets/svg/Logo_Blue.svg" type="image/svg+xml" sizes="any">
<link rel="apple-touch-icon" href="assets/png/Logo_Blue.png">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "AltDirect",
"url": "https://stikstore.app/altdirect/",
"description": "AltStore sources, simplified.",
"publisher": {
"@type": "Organization",
"name": "AltDirect",
"logo": {
"@type": "ImageObject",
"url": "https://stikstore.app/altdirect/assets/png/Logo_Blue.png"
}
}
}
</script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="old-address-banner" class="old-address-banner" role="alert" hidden>
The link you were given uses an old AltDirect address. Please ask its maintainer to update their links and embeds to the new address at <a href="https://altdirect.app/">https://altdirect.app/</a>.
</div>
<button id="theme-toggle" class="theme-toggle" aria-label="Toggle Theme"></button>
<main>
<div class="hero">
<svg width="100" height="100" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg" class="app-icon">
<path d="M167.822 256H88.1778V233.636H167.822V256ZM22.6694 187.754C23.8473 201.628 28.4122 212.443 36.1111 220.024C43.5857 227.499 54.5064 232.132 68.2667 233.325V255.778C47.4259 254.514 30.9298 247.762 19.5833 236.415C8.01834 224.973 1.46739 208.519 0.222222 187.754H22.6694ZM255.883 187.754C254.615 208.519 247.954 224.973 236.389 236.415C225.165 247.639 208.678 254.492 187.733 255.775V233.32C201.592 232.103 212.521 227.385 220 220.024C227.699 212.443 232.264 201.628 233.442 187.754H255.883ZM128 49.072C132.868 49.072 137.662 50.2665 141.961 52.5501C146.261 54.8341 149.935 58.1392 152.661 62.1734C153.236 63.0693 153.825 63.9557 154.419 64.8376L109.311 110.04C104.286 115.07 101.221 121.732 101.3 129.033C101.379 136.282 104.539 142.782 109.381 147.652L109.483 147.755L109.589 147.858C114.453 152.552 120.884 155.556 127.989 155.625C135.155 155.695 141.774 152.762 146.856 147.822L146.928 147.752L146.997 147.683L191.911 102.775C193.247 103.699 194.598 104.604 195.967 105.484C200 108.21 203.305 111.885 205.589 116.185C207.872 120.485 209.067 125.279 209.067 130.147C209.067 135.016 207.872 139.81 205.589 144.11C203.305 148.41 200 152.085 195.967 154.811C178.59 165.971 163.82 180.743 152.661 198.121C149.935 202.156 146.261 205.461 141.961 207.745C137.662 210.028 132.868 211.223 128 211.223C123.132 211.223 118.338 210.028 114.039 207.745C109.739 205.461 106.065 202.156 103.339 198.121C92.1799 180.743 77.4098 165.971 60.0333 154.811C55.9996 152.085 52.6948 148.41 50.4111 144.11C48.1277 139.81 46.9333 135.016 46.9333 130.147C46.9333 125.279 48.1277 120.485 50.4111 116.185C52.6948 111.885 55.9996 108.21 60.0333 105.484C77.4098 94.3235 92.1799 79.5517 103.339 62.1734C106.065 58.1392 109.739 54.8341 114.039 52.5501C118.338 50.2665 123.132 49.072 128 49.072ZM22.3611 167.84H0V88.1873H22.3611V167.84ZM241.778 0C250.058 1.39468e-05 256 6.38511 256 14.2238V136.74C256 144.284 251.282 149.35 244.622 149.35C237.668 149.35 233.245 143.254 233.244 136.74V102.411L234.222 38.1903L213.522 60.351L136.942 136.912C131.637 142.07 124.565 141.833 119.467 136.912C114.311 131.726 114.133 124.623 119.378 119.377L195.961 42.6407L217.772 22.4469L150.756 22.758H119.467C112.954 22.758 106.667 18.0095 106.667 11.379C106.667 4.60073 111.629 0 119.467 0H241.778ZM68.2667 22.6802C54.4758 23.8993 43.4685 28.6181 36.1111 35.9761C28.407 43.5626 23.8407 54.3863 22.6667 68.2741H0.225C1.48786 47.4952 8.13756 31.0326 19.5833 19.5855C30.8059 8.36165 47.4024 1.50656 68.2667 0.222246V22.6802Z" fill="url(#paint0_linear_120_31)"/>
<defs>
<linearGradient id="paint0_linear_120_31" x1="128" y1="0" x2="128" y2="256" gradientUnits="userSpaceOnUse">
<stop stop-color="#56B2FF"/>
<stop offset="1" stop-color="#008CFF"/>
</linearGradient>
</defs>
</svg>
<h1>Alt<span>Direct</span></h1>
<p class="description" id="tagline">Sources, simplified.</p>
<div id="subtitle" class="hint" aria-live="polite"></div>
<div id="links-container">Loading...</div>
</div>
<div class="credit">
Made by <a href="https://github.com/CelloSerenity" target="_blank" rel="noopener">CelloSerenity</a>. <a href="https://github.com/StikDebug/altdirect" target="_blank" rel="noopener">Source</a>
</div>
</main>
<script>
'use strict';
const toggleBtn = document.getElementById('theme-toggle');
const root = document.documentElement;
function isLight() {
return root.getAttribute('data-theme') === 'light' ||
(!root.hasAttribute('data-theme') && window.matchMedia('(prefers-color-scheme: light)').matches);
}
function updateIcon() {
const light = isLight();
toggleBtn.innerHTML = light
? '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>'
: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>';
}
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
root.setAttribute('data-theme', savedTheme);
}
updateIcon();
toggleBtn.addEventListener('click', () => {
const currentIsLight = isLight();
const newTheme = currentIsLight ? 'dark' : 'light';
root.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
updateIcon();
});
window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', () => {
if (!localStorage.getItem('theme')) {
updateIcon();
}
});
const container = document.getElementById('links-container');
const subtitle = document.getElementById('subtitle');
const params = new URLSearchParams(window.location.search);
const rawParam = params.get('url');
const rParam = params.get('r');
const excludeParam = params.get('exclude');
const isOldAddress = params.get('old') === 'true';
const oldAddressBanner = document.getElementById('old-address-banner');
if (isOldAddress) {
oldAddressBanner.hidden = false;
}
function setContainer(contentNode) {
container.replaceChildren(contentNode);
}
function createEl(tag, attrs, text) {
const el = document.createElement(tag);
if (attrs) for (const k in attrs) el.setAttribute(k, attrs[k]);
if (text != null) el.textContent = text;
return el;
}
function buildForm() {
subtitle.style.display = 'none';
const tagline = document.getElementById('tagline');
if (tagline) tagline.style.display = 'block';
const wrapper = createEl('div', { class: 'url-form-wrapper' });
const form = createEl('form', { id: 'url-form', class: 'url-form', autocomplete: 'off' });
const input = createEl('input', { id: 'url-input', class: 'url-input', type: 'url', placeholder: 'Enter Source URL...', 'aria-label': 'Source URL' });
const pasteBtn = createEl('button', { type: 'button', id: 'paste-btn', class: 'paste-button', title: 'Paste' });
pasteBtn.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>';
const submitBtn = createEl('button', { type: 'submit', class: 'submit-button', title: 'Go' });
submitBtn.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>';
const errorEl = createEl('div', { id: 'url-error', class: 'error' });
errorEl.style.display = 'none';
form.append(input, pasteBtn, submitBtn);
wrapper.append(form, errorEl);
setTimeout(() => { try { input.focus(); } catch (_) {} }, 50);
pasteBtn.addEventListener('click', async () => {
errorEl.style.display = 'none';
try {
if (!navigator.clipboard || !navigator.clipboard.readText) throw new Error();
const text = await navigator.clipboard.readText();
input.value = text;
} catch (_) {
errorEl.textContent = 'Unable to read clipboard.';
errorEl.style.display = 'block';
}
});
form.addEventListener('submit', (ev) => {
ev.preventDefault();
const rawVal = (input.value || '').trim();
if (!rawVal) {
errorEl.textContent = 'Please enter a valid URL.';
errorEl.style.display = 'block';
input.focus();
return;
}
const excludePart = excludeParam ? '&exclude=' + excludeParam : '';
const oldAddressPart = isOldAddress ? '&old=true' : '';
window.location.href = window.location.pathname + '?url=' + rawVal + excludePart + oldAddressPart;
});
return wrapper;
}
function replaceQueryParam(qs, key, val) {
const q = qs ? qs.replace(/^\?/, '') : '';
const parts = q ? q.split('&') : [];
const filtered = [];
for (let i = 0; i < parts.length; i++) {
const p = parts[i];
if (!p) continue;
const k = p.split('=')[0];
if (k !== key) filtered.push(p);
}
if (val != null) filtered.push(key + '=' + val);
return filtered.join('&');
}
function buildLinks(s, excludeList) {
subtitle.textContent = 'Choose your sideloader:';
subtitle.style.display = 'block';
const tagline = document.getElementById('tagline');
if (tagline) tagline.style.display = 'none';
const frag = document.createDocumentFragment();
const urlDisplay = createEl('div', { class: 'source-url-display' }, s);
frag.appendChild(urlDisplay);
function hrefWithR(choice) {
const loc = window.location;
const newQs = replaceQueryParam(loc.search, 'r', choice);
return loc.pathname + (newQs ? '?' + newQs : '');
}
const linkMap = [
{ key: 'altstore', label: 'Open in AltStore Classic', href: hrefWithR('altstore'), cls: 'altstore' },
{ key: 'feather', label: 'Open in Feather', href: hrefWithR('feather'), cls: 'feather' },
{ key: 'livecontainer', label: 'Open in LiveContainer', href: hrefWithR('livecontainer'), cls: 'livecontainer' },
{ key: 'sidestore', label: 'Open in SideStore', href: hrefWithR('sidestore'), cls: 'sidestore' },
{ key: 'stikstore', label: 'Open in StikStore', href: hrefWithR('stikstore'), cls: 'stikstore' },
{ key: 'trollapps', label: 'Open in TrollApps', href: hrefWithR('trollapps'), cls: 'trollapps' }
];
for (let i = 0; i < linkMap.length; i++) {
const item = linkMap[i];
if (excludeList.includes(item.key)) continue;
const a = createEl('a', { class: 'custom-button ' + item.cls, href: item.href, target: '_self', rel: 'noopener' }, item.label);
frag.appendChild(a);
}
const copyBtn = createEl('button', { class: 'custom-button neutral', id: 'copy-link-btn', type: 'button' }, 'Copy Source URL');
copyBtn.addEventListener('click', function () {
const self = this;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(s).then(() => {
const prev = self.textContent;
self.textContent = 'Copied!';
setTimeout(() => { self.textContent = prev; }, 1500);
});
}
});
const viewBtn = createEl('button', { class: 'custom-button neutral', id: 'view-source-btn', type: 'button' }, 'View Source Data');
viewBtn.addEventListener('click', () => {
window.open(s, '_blank', 'noopener,noreferrer');
});
frag.append(copyBtn, viewBtn);
return frag;
}
if (!rawParam && !rParam) {
setContainer(buildForm());
} else if (rawParam) {
let s = rawParam.replace(/^(?:%20|\s)+|(?:%20|\s)+$/g, '');
if (!/^https?:\/\//i.test(s)) s = 'https://' + s;
const excludeList = (excludeParam || '').split(',').map(x => x.trim().toLowerCase()).filter(Boolean);
try {
if (window.history && history.replaceState) {
const parts = [];
parts.push('url=' + s);
if (rParam) parts.push('r=' + rParam);
if (excludeParam) parts.push('exclude=' + excludeParam);
if (isOldAddress) parts.push('old=true');
const newUrl = window.location.pathname + (parts.length ? '?' + parts.join('&') : '');
history.replaceState(null, '', newUrl);
}
} catch (e) {
// ignore
}
setContainer(buildLinks(s, excludeList));
}
</script>
<script src="redirect.js"></script>
</body>
</html>