Skip to content

Commit 6c75578

Browse files
committed
Readme patch
1 parent 5a0b6ea commit 6c75578

2 files changed

Lines changed: 80 additions & 12 deletions

File tree

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,40 @@
11
# Flean
22
Convert Yucky Fandom URLs to Breezewiki URLs
3+
4+
> **Info:** Use Chrome or Firefox, use https://getindie.wiki instead :)
5+
6+
## How it works
7+
8+
Flean is a small Safari Web Extension (with native host helpers) that redirects visits to Fandom wiki pages to independent mirrors. The goal is to provide fast, privacy-friendly redirects to community-hosted wiki mirrors.
9+
10+
- Extension core files
11+
- `ios/extention/Resources/manifest.json` — extension metadata and entry points.
12+
- `ios/extention/Resources/popup.html`, `popup.js`, `popup.css` — popup UI where the user picks a mirror, toggles "ask on visit", and manages an ignore list.
13+
- `ios/extention/Resources/content.js` / `background.js` — runtime logic that runs on visited pages and computes redirects.
14+
- Optional mapping files (not required) — the extension can use an internal mapping or external mapping files to associate Fandom hosts with mirror destinations (destBase + destPath). If no mapping is present the extension falls back to simple heuristics to build candidate mirror URLs.
15+
16+
- Runtime flow
17+
1. The content script detects the current host (for example `deltarune.fandom.com`) and either looks it up in an internal mapping (if provided) or computes candidate mirror hosts using simple heuristics.
18+
2. If a candidate destination is determined it constructs the destination URL (base domain + path) plus the article/title from the original path.
19+
3. Depending on settings (`askOnVisit`, ignore/allow lists), the extension either redirects immediately or prompts the user via the popup to confirm.
20+
21+
- Native host (macOS / iOS)
22+
- The repository includes a tiny macOS app and an iOS WebView host that can load the same `Main.html` UI. The native host exposes a `controller` script message handler so the web UI can get/set settings and persist them to Application Support.
23+
- On iOS the app stores settings in `Application Support/Flean/settings.json` (see `ios/Flean/iOS/SettingsStore.swift`) and pushes updates into the web UI via `CustomEvent('flean:message')`.
24+
25+
- Test harness
26+
- For quick local testing I added a small PHP-based test harness at the repo root:
27+
- `index.php` — loads the popup UI in an iframe and provides a form to test redirect generation.
28+
- `redirect.php` — server-side endpoint that uses a small built-in mapping or simple heuristics to return a candidate redirect URL for a provided `?url=` parameter. It does not require a compiled datapack to be present.
29+
- To run the test harness locally (PHP required):
30+
```bash
31+
# from the repo root
32+
php -S localhost:8000 -t /Users/kiyarose/Documents/GitStuff/Flean
33+
# then open http://localhost:8000/ in your browser
34+
```
35+
36+
If you want I can further:
37+
- Make the popup UI gracefully fall back to the test harness API when running in a regular browser (so the iframe is fully interactive).
38+
- Improve the redirect generator to preserve queries/fragments and do safer percent-encoding when composing mirror URLs.
39+
- Add App Group entitlements if you want the extension and native host to share settings directly (this requires provisioning updates).
40+

redirect.php

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ function load_datapack($path) {
1919
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) return $decoded;
2020
}
2121

22-
// As a last resort, return the raw string so the UI can show a preview
22+
// As a last resort, return null
2323
return null;
2424
}
2525

2626
if (isset($_GET['preview'])) {
2727
// Return a short preview of the datapack file
2828
if (!file_exists($datapackPath)) {
29-
echo json_encode(['error' => 'datapack not found']);
29+
echo json_encode(['preview' => null, 'note' => 'no compiled mapping file present; using heuristics']);
3030
exit;
3131
}
3232
$raw = file_get_contents($datapackPath);
@@ -57,14 +57,8 @@ function load_datapack($path) {
5757
'reason' => ''
5858
];
5959

60-
if ($dat === null) {
61-
$result['reason'] = 'datapack unreadable or invalid JSON';
62-
echo json_encode($result);
63-
exit;
64-
}
65-
66-
// Exact host match
67-
if (isset($dat[$host])) {
60+
// Exact host match from datapack
61+
if (is_array($dat) && isset($dat[$host])) {
6862
$entry = $dat[$host];
6963
$destBase = isset($entry['destBase']) ? $entry['destBase'] : '';
7064
$destPath = isset($entry['destPath']) ? $entry['destPath'] : '/';
@@ -103,8 +97,16 @@ function load_datapack($path) {
10397
$redirect .= $destPath;
10498
if ($article !== '') {
10599
if (substr($redirect, -1) !== '/') $redirect .= '/';
106-
$redirect .= $article;
100+
$redirect .= rawurlencode($article);
101+
}
102+
103+
// Preserve query and fragment if present (basic handling)
104+
parse_str($query, $qparts);
105+
if (!empty($qparts)) {
106+
if (isset($qparts['title'])) unset($qparts['title']);
107+
if (!empty($qparts)) $redirect .= '?' . http_build_query($qparts);
107108
}
109+
if (isset($parsed['fragment']) && $parsed['fragment']) $redirect .= '#' . $parsed['fragment'];
108110

109111
$result['matched'] = true;
110112
$result['redirect'] = $redirect;
@@ -113,5 +115,33 @@ function load_datapack($path) {
113115
exit;
114116
}
115117

116-
$result['reason'] = 'no mapping for host in datapack';
118+
// Heuristics fallback: try to convert .fandom.com -> .wiki.gg and use /wiki/ path
119+
if (substr($host, -11) === '.fandom.com') {
120+
$base = substr($host, 0, -11) . '.wiki.gg';
121+
// Extract title preferring /wiki/ or query title
122+
$article = '';
123+
if (strpos($path, '/wiki/') === 0) {
124+
$article = substr($path, strlen('/wiki/'));
125+
} else {
126+
parse_str($query, $q);
127+
if (!empty($q['title'])) $article = $q['title'];
128+
else $article = ltrim($path, '/');
129+
}
130+
131+
$redirect = 'https://' . rtrim($base, '/') . '/wiki/' . rawurlencode($article);
132+
parse_str($query, $qparts);
133+
if (!empty($qparts)) {
134+
if (isset($qparts['title'])) unset($qparts['title']);
135+
if (!empty($qparts)) $redirect .= '?' . http_build_query($qparts);
136+
}
137+
if (isset($parsed['fragment']) && $parsed['fragment']) $redirect .= '#' . $parsed['fragment'];
138+
139+
$result['matched'] = true;
140+
$result['redirect'] = $redirect;
141+
$result['used'] = 'heuristic';
142+
echo json_encode($result);
143+
exit;
144+
}
145+
146+
$result['reason'] = 'no mapping or heuristic available for host';
117147
echo json_encode($result);

0 commit comments

Comments
 (0)