Skip to content

Instantly share code, notes, and snippets.

@MaxEtMoritz
Last active July 11, 2023 08:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MaxEtMoritz/dd4519a181823d6094ed3da0d6eec9da to your computer and use it in GitHub Desktop.
Save MaxEtMoritz/dd4519a181823d6094ed3da0d6eec9da to your computer and use it in GitHub Desktop.
Woov (https://woov.com/) event timetable to ical. Designed to run in NodeJS, but can be adapted for browser if needed.
const fs = require('fs');
const { exit } = require('process');
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
const prompt = query => new Promise(resolve => rl.question(query, resolve));
const query = `
query ($eid: ID!, $after: String) {
event(eventId: $eid) {
shows(first: 100, after: $after) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
start
end
artists {
name
links {
url
}
description
}
stage {
name
# description
}
}
}
}
}
}
`;
(async () => {
var flat = [];
let nextPage = true;
let endCursor = null;
const eventId = await prompt('enter your Woov Event ID (see Woov Invite link like https://gowoov.com/event/XXXXX): ');
do {
let body = JSON.stringify({
query,
variables: {
eid: eventId,
after: endCursor
}
})
let response = await (
await fetch('https://api.woov.nl/graphql',{
method: 'POST',
body,
headers:{
'Content-Type': 'application/json'
}
})
).json();
if (response.errors) {
throw new Error(response.errors[0].message);
}
nextPage = response.data.event.shows.pageInfo.hasNextPage;
endCursor = response.data.event.shows.pageInfo.endCursor;
flat.push(...response.data.event.shows.edges.map(e => e.node));
console.log('loaded', flat.length, 'shows.')
} while (nextPage);
var ics = `BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
`;
ics += flat.map(n => {
let start = new Date(n.start);
let end = new Date(n.end);
let desc = n.artists[0].description ?? '';
if (n.artists[0].links.length > 0) {
desc += '\n\nLinks:\n';
desc += n.artists[0].links.map(l => l.url).join('\n');
}
function icalDate(jsDate) {
let result = '';
result += jsDate.getFullYear().toString().padStart(4, '0');
result += (jsDate.getMonth() + 1).toString().padStart(2, '0');
result += jsDate.getDate().toString().padStart(2, '0');
result += 'T' + jsDate.getHours().toString().padStart(2, '0');
result += jsDate.getMinutes().toString().padStart(2, '0');
result += jsDate.getSeconds().toString().padStart(2, '0');
return result;
}
return `SUMMARY:${n.artists.map(a => a.name).join(' & ')}
DTSTAMP:${icalDate(start)}
DESCRIPTION:${desc.replace(/\r?\n/g, '\\n')}
DTSTART:${icalDate(start)}
DTEND:${icalDate(end)}
LOCATION:${n.stage.name}`;
}).join(`
END:VEVENT
BEGIN:VEVENT
`);
ics += `
END:VEVENT
END:VCALENDAR
`;
fs.writeFileSync('timetable_2.ics', ics);
console.log('done')
exit(0)
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment