···
60
60
);
61
61
}
62
62
63
63
+
// Special case for mackuba.eu - hardcoded workaround for third-party PDS
64
64
+
if (handle === 'mackuba.eu') {
65
65
+
console.log('SPECIAL CASE: mackuba.eu detected, using hardcoded solution');
66
66
+
try {
67
67
+
// Use public API to resolve the DID first
68
68
+
const resolveResponse = await fetch(`https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle?handle=mackuba.eu`);
69
69
+
if (!resolveResponse.ok) {
70
70
+
return NextResponse.json({ error: 'Failed to resolve mackuba.eu handle' }, { status: resolveResponse.status });
71
71
+
}
72
72
+
73
73
+
const resolveData = await resolveResponse.json();
74
74
+
const did = resolveData.did;
75
75
+
76
76
+
// Get profile data
77
77
+
const profileResponse = await fetch(`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=mackuba.eu`);
78
78
+
let userProfile = null;
79
79
+
if (profileResponse.ok) {
80
80
+
userProfile = await profileResponse.json();
81
81
+
}
82
82
+
83
83
+
// Directly call the PDS we know works
84
84
+
const directUrl = `https://lab.martianbase.net/xrpc/com.atproto.repo.listRecords?repo=${encodeURIComponent(did)}&collection=im.flushing.right.now&limit=50`;
85
85
+
console.log(`Making direct request to: ${directUrl}`);
86
86
+
87
87
+
const directResponse = await fetch(directUrl, {
88
88
+
headers: { 'Accept': 'application/json' }
89
89
+
});
90
90
+
91
91
+
if (!directResponse.ok) {
92
92
+
// If we get a 404, return empty data rather than error
93
93
+
if (directResponse.status === 404) {
94
94
+
return NextResponse.json({
95
95
+
entries: [],
96
96
+
count: 0,
97
97
+
profile: userProfile,
98
98
+
emojiStats: [],
99
99
+
did,
100
100
+
handle: 'mackuba.eu',
101
101
+
directUrl,
102
102
+
emptyCollection: true
103
103
+
});
104
104
+
}
105
105
+
106
106
+
return NextResponse.json({
107
107
+
error: `Failed to fetch mackuba.eu records: ${directResponse.statusText}`,
108
108
+
directUrl
109
109
+
}, { status: directResponse.status });
110
110
+
}
111
111
+
112
112
+
const recordsData = await directResponse.json();
113
113
+
114
114
+
// Transform the records into our format
115
115
+
const transformedEntries = recordsData.records
116
116
+
.map((record: any) => {
117
117
+
const text = record.value.text || '';
118
118
+
119
119
+
// Skip entries with banned content
120
120
+
if (containsBannedWords(text)) {
121
121
+
return null;
122
122
+
}
123
123
+
124
124
+
return {
125
125
+
id: record.uri,
126
126
+
uri: record.uri,
127
127
+
cid: record.cid,
128
128
+
did: did,
129
129
+
text: sanitizeText(text),
130
130
+
emoji: record.value.emoji || '🚽',
131
131
+
created_at: record.value.createdAt
132
132
+
};
133
133
+
})
134
134
+
.filter((entry: ProfileEntry | null): entry is ProfileEntry => entry !== null);
135
135
+
136
136
+
// Calculate emoji statistics
137
137
+
const emojiCounts = new Map<string, number>();
138
138
+
139
139
+
// Process entries to count emojis
140
140
+
transformedEntries.forEach((entry: ProfileEntry) => {
141
141
+
const emoji = entry.emoji?.trim() || '🚽';
142
142
+
if (APPROVED_EMOJIS.includes(emoji)) {
143
143
+
emojiCounts.set(emoji, (emojiCounts.get(emoji) || 0) + 1);
144
144
+
} else {
145
145
+
emojiCounts.set('🚽', (emojiCounts.get('🚽') || 0) + 1);
146
146
+
}
147
147
+
});
148
148
+
149
149
+
const emojiStats = Array.from(emojiCounts.entries())
150
150
+
.map(([emoji, count]): EmojiStat => ({ emoji, count }))
151
151
+
.sort((a, b) => b.count - a.count);
152
152
+
153
153
+
return NextResponse.json({
154
154
+
entries: transformedEntries,
155
155
+
count: transformedEntries.length,
156
156
+
cursor: recordsData.cursor,
157
157
+
profile: userProfile,
158
158
+
emojiStats,
159
159
+
serviceEndpoint: 'https://lab.martianbase.net',
160
160
+
directUrl,
161
161
+
specialCase: true
162
162
+
});
163
163
+
} catch (specialErr: any) {
164
164
+
console.error(`Error in special handling for mackuba.eu:`, specialErr);
165
165
+
return NextResponse.json({
166
166
+
error: `Special handling for mackuba.eu failed: ${specialErr.message}`,
167
167
+
workingUrl: 'https://lab.martianbase.net/xrpc/com.atproto.repo.listRecords?repo=did:plc:oio4hkxaop4ao4wz2pp3f4cr&collection=im.flushing.right.now&limit=100'
168
168
+
}, { status: 500 });
169
169
+
}
170
170
+
}
171
171
+
63
172
// Special case for plumber account redirect
64
173
if (handle === 'plumber.flushing.im') {
65
174
console.log('Redirecting from old plumber.flushing.im handle to plumber.flushes.app');