-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathdecode_share_link.html
More file actions
218 lines (170 loc) · 6.66 KB
/
decode_share_link.html
File metadata and controls
218 lines (170 loc) · 6.66 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
<!-- =======================================================================================
ABC TRANSCRIPTION TOOLS SHARE LINK DECODER
=========================================================================================
PURPOSE
-------
Extract the original ABC text from a share link containing either:
?lzw=<payload> (LZ-String compression)
?def=<payload> (Deflate + Base64URL compression)
This module allows 3rd-party developers to decode ABC share links
generated by the ABC Transcription Tools.
-----------------------------------------------------------------------------------------
REQUIRED LIBRARIES
-----------------------------------------------------------------------------------------
1) For lzw= links:
Include lz-string.min.js
Uses: LZString.decompressFromEncodedURIComponent()
2) For def= links:
Include pako.min.js
Uses: pako.inflate()
Also requires:
- TextDecoder (modern browsers)
- atob() (standard browser API)
-----------------------------------------------------------------------------------------
HOW SHARE LINKS ARE ENCODED
-----------------------------------------------------------------------------------------
LZW MODE (standard / legacy):
lzw = LZString.compressToEncodedURIComponent(abcText)
DEF MODE (often shorter for larger ABC):
1) UTF8 encode ABC
2) Deflate bytes (pako.deflate)
3) Base64 encode
4) Convert to Base64URL:
'+' → '-'
'/' → '_'
strip trailing '='
-----------------------------------------------------------------------------------------
HOW TO USE THIS DECODER
-----------------------------------------------------------------------------------------
const result = decodeABCFromShareLink(url);
result = {
mode: "lzw" | "deflate",
abc: "<decoded ABC text>"
}
-----------------------------------------------------------------------------------------
ERROR / NULL HANDLING (IMPORTANT)
-----------------------------------------------------------------------------------------
In LZW mode:
- LZString.decompressFromEncodedURIComponent() may return NULL.
- NULL indicates a decoding failure.
Common causes:
• The URL was truncated (length limits, email wrapping, messaging apps)
• Characters were modified during copy/paste
• The wrong decompression function was used
In Deflate mode:
- Base64URL length errors indicate corruption or truncation.
- pako.inflate() throws if compressed bytes are invalid.
In either case:
- Treat failures as "invalid or corrupted share link".
======================================================================================= -->
<script>
/* =========================================================================================
Base64URL → Bytes Helpers (Used for def= decoding)
========================================================================================= */
/**
* Convert normal Base64 string to Uint8Array.
*/
function base64ToBytes(base64) {
const binary = atob(base64);
const len = binary.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
/**
* Convert Base64URL string to Uint8Array.
*
* Base64URL differences:
* '-' instead of '+'
* '_' instead of '/'
* '=' padding removed
*
* We reverse these changes before decoding.
*/
function base64URLToBytes(base64url) {
let base64 = base64url
.replace(/-/g, "+")
.replace(/_/g, "/");
// Restore required '=' padding
const pad = base64.length % 4;
if (pad === 2) base64 += "==";
else if (pad === 3) base64 += "=";
else if (pad !== 0) {
throw new Error("Invalid Base64URL length. Payload may be truncated or corrupted.");
}
return base64ToBytes(base64);
}
/* =========================================================================================
MAIN DECODER FUNCTION
========================================================================================= */
/**
* Decode ABC text from an ABC Tools share link.
*
* @param {string} urlOrQueryString
* Can be:
* - Full URL (https://...abctools.html?lzw=...)
* - Just the query string (?lzw=...&format=...)
*
* @returns {{ mode: "lzw"|"deflate", abc: string }}
*
* @throws Error if:
* - No payload parameter found
* - Required library missing
* - Decoding fails
*/
function decodeABCFromShareLink(urlOrQueryString) {
if (!urlOrQueryString) {
throw new Error("No URL or query string provided.");
}
// Extract query string if full URL was passed
let query = urlOrQueryString;
if (query.includes("?")) {
query = query.split("?")[1];
}
const params = new URLSearchParams(query);
const lzw = params.get("lzw");
const def = params.get("def");
/* -----------------------------------------------------------------------
LZW MODE
----------------------------------------------------------------------- */
if (lzw != null) {
if (typeof LZString === "undefined") {
throw new Error("LZString library not loaded. Required for lzw= decoding.");
}
const abc = LZString.decompressFromEncodedURIComponent(lzw);
// CRITICAL: null means decompression failed
if (abc === null) {
throw new Error(
"LZW decompression returned null.\n" +
"This indicates a corrupted or truncated share link.\n" +
"Verify the entire lzw= value is intact."
);
}
return { mode: "lzw", abc };
}
/* -----------------------------------------------------------------------
DEFLATE MODE
----------------------------------------------------------------------- */
if (def != null) {
if (typeof pako === "undefined") {
throw new Error("pako library not loaded. Required for def= decoding.");
}
if (typeof TextDecoder === "undefined") {
throw new Error("TextDecoder not available. Required for UTF-8 decoding.");
}
// Step 1: Base64URL → raw compressed bytes
const deflatedBytes = base64URLToBytes(def);
// Step 2: Inflate (DEFLATE decompression)
const inflatedBytes = pako.inflate(deflatedBytes);
// Step 3: UTF-8 decode to JS string
const abc = new TextDecoder().decode(inflatedBytes);
return { mode: "deflate", abc };
}
/* -----------------------------------------------------------------------
NO PAYLOAD FOUND
----------------------------------------------------------------------- */
throw new Error("No lzw= or def= parameter found in the URL.");
}
</script>