Initial commit — OFApp client + server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-12 20:07:06 -06:00
commit c60de19348
43 changed files with 8679 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
async function request(url, options = {}) {
try {
const response = await fetch(url, options);
const data = await response.json();
if (!response.ok) {
let errMsg = data.error || data.message || `Request failed with status ${response.status}`;
if (typeof errMsg === 'object') errMsg = errMsg.message || errMsg.error || JSON.stringify(errMsg);
return { error: String(errMsg) };
}
// OF API sometimes returns 200 with error body like {code, message} instead of proper HTTP error
if (data && typeof data.code !== 'undefined' && !data.id) {
return { error: data.message || 'Request failed' };
}
return data;
} catch (err) {
return { error: err.message || 'Network error' };
}
}
function buildQuery(params) {
const query = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null && value !== '') {
query.set(key, value);
}
}
const str = query.toString();
return str ? `?${str}` : '';
}
export function getMe() {
return request('/api/me');
}
export function getFeed(beforePublishTime) {
const query = buildQuery({ beforePublishTime });
return request(`/api/feed${query}`);
}
export function getSubscriptions(offset) {
const query = buildQuery({ offset });
return request(`/api/subscriptions${query}`);
}
export function getUserPosts(userId, beforePublishTime) {
const query = buildQuery({ beforePublishTime });
return request(`/api/users/${userId}/posts${query}`);
}
export function getUser(username) {
return request(`/api/users/${username}`);
}
export function saveAuth(config) {
return request('/api/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(config),
});
}
export function getAuth() {
return request('/api/auth');
}
export function startDownload(userId, limit, resume, username) {
const body = {};
if (limit) body.limit = limit;
if (resume) body.resume = true;
if (username) body.username = username;
return request(`/api/download/${userId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
}
export function getDownloadStatus(userId) {
return request(`/api/download/${userId}/status`);
}
export function getActiveDownloads() {
return request('/api/download/active');
}
export function getDownloadCursor(userId) {
return request(`/api/download/${userId}/cursor`);
}
export function getDownloadHistory() {
return request('/api/download/history');
}
export function getGalleryFolders() {
return request('/api/gallery/folders');
}
export function getSettings() {
return request('/api/settings');
}
export function updateSettings(settings) {
return request('/api/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(settings),
});
}
export function getGalleryFiles({ folder, folders, type, sort, offset, limit } = {}) {
const query = buildQuery({ folder, folders: folders ? folders.join(',') : undefined, type, sort, offset, limit });
return request(`/api/gallery/files${query}`);
}