import express from 'express'; import { Client, cacheExchange, fetchExchange, gql } from '@urql/core'; import { EpisodeResponse } from './types'; import { transformEpisode, transformEpisodeList } from './mappings'; const app = express(); const PORT = 3000; const root = "https://social.audiothek.de/@blaue-couch" const audiothekApi = new Client({ url: 'https://api.ardaudiothek.de/graphql', exchanges: [cacheExchange, fetchExchange], }); const query = gql` query Item { item(id: "14278953") { show { coreId externalId title url publisher: publicationService { coreId dvbServiceId title url organizationName organization { name url } } coreDocument } assetId url: sharingUrl title description published: publishDate updated: core(key: "modified") imagesList { url title } coreDocument audioList { title audioCodec href } } } `; async function fetchData<R>(query: any, variables: any) { const result = await audiothekApi.query<R>(query, variables).toPromise(); if (result.error) { throw result.error; } // console.log(JSON.stringify(result.data, null, 2)); return result.data; } async function main() { const response = await fetchData<EpisodeResponse>(query, { id: '14278953' }); if (response) { const activityPubEpisode = transformEpisode(response); console.log(JSON.stringify(activityPubEpisode, null, 2)); } } // main(); app.get('/:actor/episodes/:id', async (req, res) => { try { const data = await fetchData<EpisodeResponse>(query, { id: req.params.id }); if (!data) { res.status(404).json({ error: 'Episode not found' }); return; } // TODO: verifiy that the actor is the same as the attributedTo field const activityPubDocument = transformEpisode(data); res.json(activityPubDocument); } catch (error) { res.status(500).json({ error: 'Failed to fetch episode data' }); } }); app.get('/:actor/episodes', async (req, res) => { const offset = 10 * ((+req.query.page! || 1) - 1); const query = gql` query ShowWithEpisodes($showId: ID!, $first: Int = 10, $offset: Int) { show(id: $showId) { coreId externalId title url items(first: $first, orderBy: PUBLISH_DATE_DESC, offset: $offset, condition: { isPublished: true }) { nodes { assetId title url: sharingUrl } } publisher: publicationService { coreId dvbServiceId title url organizationName organization { name url } } } } `; try { // TODO: verifiy that the actor is the same as the attributedTo field const data = await fetchData<any>(query, { showId: "urn:ard:show:a42d1ea0b4a07053", offset }); if (!data) { res.status(404).json({ error: 'Episode not found' }); return; } const activityPubDocument = transformEpisodeList(data); res.json(activityPubDocument); } catch (error) { res.status(500).json({ error: 'Failed to fetch episode data' }); } }); app.get('/:actor/outbox', async (req, res) => { const query = gql` query ShowEpisodeTotal($showId: ID!) { show(id: $showId) { coreId externalId title url items(condition: { isPublished: true }) { totalCount } } }`; const data = await fetchData<any>(query, { showId: "urn:ard:show:a42d1ea0b4a07053" }); if (!data) { res.status(404).json({ error: 'Show not found' }); return; } const { totalCount } = data.show.items; res.json({ "@context": "https://www.w3.org/ns/activitystreams", "id": `${root}/outbox`, "type": "OrderedCollection", "to": [ "https://www.w3.org/ns/activitystreams#Public" ], "totalItems": totalCount, "first": `${root}/episodes?page=1`, "current": `${root}/outbox`, "last": `${root}/episodes?page=${Math.floor(totalCount/10)}` }); }); app.get('/:actor', async (req, res) => { res.json({ "@context": "https://www.w3.org/ns/activitystreams", "id": "urn:ard:show:a42d1ea0b4a07053", "type": "Service", "name": "Blaue Couch", "externalId": "https://feeds.br.de/blaue-couch/feed.xml", "attributedTo": "urn:ard:publisher:c4a9cee041835529", "publisher": { "type": "BroadcastService", "name": "BAYERN 1", "url": "https://www.ardaudiothek.de/radio/br/bayern-1/", "organization": { "type": "Organization", "name": "BR", "url": "https://www.ardaudiothek.de/radio/br/" } } }); }); app.get('/', (req, res) => res.redirect('/@blaue-couch')); app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); });