@@ -25,32 +25,40 @@ export const currentView = writable<View>({ type: 'catalog' });
2525
2626/**
2727 * Parse a hash URL into a View object
28+ * Falls back to catalog if URL cannot be parsed (e.g., malformed percent-encoding)
2829 */
2930export function parseHash ( hash : string ) : View {
30- const path = hash . replace ( / ^ # \/ ? / , '' ) ;
31- const segments = path . split ( '/' ) . filter ( Boolean ) ;
31+ try {
32+ const path = hash . replace ( / ^ # \/ ? / , '' ) ;
33+ const segments = path . split ( '/' ) . filter ( Boolean ) ;
34+
35+ if ( segments . length === 0 || segments [ 0 ] === 'catalog' ) {
36+ return { type : 'catalog' } ;
37+ }
38+ if ( segments [ 0 ] === 'cloud' ) return { type : 'cloud' } ;
39+ if ( segments [ 0 ] === 'upload' ) return { type : 'upload' } ;
40+ if ( segments [ 0 ] === 'reading-speed' ) return { type : 'reading-speed' } ;
41+
42+ if ( segments [ 0 ] === 'series' && segments . length >= 2 ) {
43+ const seriesId = decodeURIComponent ( segments [ 1 ] ) ;
44+ if ( segments [ 2 ] === 'text' ) return { type : 'series-text' , seriesId } ;
45+ return { type : 'series' , seriesId } ;
46+ }
47+
48+ if ( segments [ 0 ] === 'reader' && segments . length >= 3 ) {
49+ const seriesId = decodeURIComponent ( segments [ 1 ] ) ;
50+ const volumeId = decodeURIComponent ( segments [ 2 ] ) ;
51+ if ( segments [ 3 ] === 'text' ) return { type : 'volume-text' , seriesId, volumeId } ;
52+ return { type : 'reader' , seriesId, volumeId } ;
53+ }
3254
33- if ( segments . length === 0 || segments [ 0 ] === 'catalog' ) {
55+ return { type : 'catalog' } ;
56+ } catch {
57+ // decodeURIComponent can throw URIError on malformed percent-encoding
58+ // Fall back to catalog page if URL cannot be parsed
59+ console . warn ( 'Failed to parse URL hash, redirecting to catalog:' , hash ) ;
3460 return { type : 'catalog' } ;
3561 }
36- if ( segments [ 0 ] === 'cloud' ) return { type : 'cloud' } ;
37- if ( segments [ 0 ] === 'upload' ) return { type : 'upload' } ;
38- if ( segments [ 0 ] === 'reading-speed' ) return { type : 'reading-speed' } ;
39-
40- if ( segments [ 0 ] === 'series' && segments . length >= 2 ) {
41- const seriesId = decodeURIComponent ( segments [ 1 ] ) ;
42- if ( segments [ 2 ] === 'text' ) return { type : 'series-text' , seriesId } ;
43- return { type : 'series' , seriesId } ;
44- }
45-
46- if ( segments [ 0 ] === 'reader' && segments . length >= 3 ) {
47- const seriesId = decodeURIComponent ( segments [ 1 ] ) ;
48- const volumeId = decodeURIComponent ( segments [ 2 ] ) ;
49- if ( segments [ 3 ] === 'text' ) return { type : 'volume-text' , seriesId, volumeId } ;
50- return { type : 'reader' , seriesId, volumeId } ;
51- }
52-
53- return { type : 'catalog' } ;
5462}
5563
5664/**
0 commit comments