Compare commits

..

7 Commits

3 changed files with 101 additions and 59 deletions

View File

@ -4,19 +4,38 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calendar Merger</title>
<link rel="stylesheet" href="/styles.css">
<style>
body {
font-family: Arial, sans-serif;
}
#calendars {
margin-bottom: 20px;
}
#calendars .calendar {
margin-bottom: 10px;
}
#calendars .calendar input[type="text"] {
width: 50%;
margin-right: 10px;
}
#calendars .calendar input[type="url"] {
width: 50%;
}
#add-calendar {
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>Calendar Merger</h1>
<form id="merge-form">
<label for="cal1-url">Calendar 1 URL:</label>
<input type="url" id="cal1-url" name="cal1-url"><br><br>
<label for="cal1-prefix">Calendar 1 Prefix:</label>
<input type="text" id="cal1-prefix" name="cal1-prefix"><br><br>
<label for="cal2-url">Calendar 2 URL:</label>
<input type="url" id="cal2-url" name="cal2-url"><br><br>
<label for="cal2-prefix">Calendar 2 Prefix:</label>
<input type="text" id="cal2-prefix" name="cal2-prefix"><br><br>
<div id="calendars">
<div class="calendar">
<input type="text" id="prefix-0" placeholder="Prefix">
<input type="url" id="url-0" placeholder="Calendar URL">
</div>
</div>
<button id="add-calendar" type="button">Add Calendar</button>
<button type="submit">Merge Calendars</button>
</form>
<div id="result"></div>
@ -24,3 +43,4 @@
<script src="script.js"></script>
</body>
</html>

View File

@ -1,31 +1,42 @@
const form = document.getElementById('merge-form');
const resultDiv = document.getElementById('result');
const calendars = document.getElementById('calendars');
const addCalendarButton = document.getElementById('add-calendar');
const result = document.getElementById('result');
form.addEventListener('submit', (e) => {
e.preventDefault();
const cal1Url = document.getElementById('cal1-url').value;
const cal1Prefix = document.getElementById('cal1-prefix').value;
const cal2Url = document.getElementById('cal2-url').value;
const cal2Prefix = document.getElementById('cal2-prefix').value;
let calendarIndex = 1;
fetch('/merge', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
cal1Url,
cal1Prefix,
cal2Url,
cal2Prefix
})
})
.then(response => response.json())
.then((data) => {
resultDiv.innerHTML = `Merged calendar URL: <a href="${data.url}" target="_blank">${data.url}</a>`;
})
.catch((error) => {
console.error(error);
resultDiv.innerHTML = 'Error merging calendars';
});
});
addCalendarButton.addEventListener('click', () => {
const newCalendar = document.createElement('div');
newCalendar.className = 'calendar';
newCalendar.innerHTML = `
<input type="text" id="prefix-${calendarIndex}" placeholder="Prefix">
<input type="url" id="url-${calendarIndex}" placeholder="Calendar URL">
`;
calendars.appendChild(newCalendar);
calendarIndex++;
});
form.addEventListener('submit', (event) => {
event.preventDefault();
const calendarsData = [];
for (let i = 0; i < calendarIndex; i++) {
const prefix = document.getElementById(`prefix-${i}`).value;
const url = document.getElementById(`url-${i}`).value;
calendarsData.push({ prefix, url });
}
fetch('/merge', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ calendars: calendarsData })
})
.then((response) => response.json())
.then((data) => {
result.innerHTML = `Merged calendar URL: <a href="${data.url}">${data.url}</a>`;
})
.catch((error) => {
console.error(error);
result.innerHTML = 'Error merging calendars';
});
});

View File

@ -14,36 +14,46 @@ app.get('/', (req, res) => {
});
app.post('/merge', async (req, res) => {
const { cal1Url, cal1Prefix, cal2Url, cal2Prefix } = req.body;
const { calendars } = req.body;
try {
//validate the input
if (!calendars || !Array.isArray(calendars)) {
return res.status(400).json({ error: 'Invalid input' });
}
// Fetch calendar data from URLs
const cal1Data = await axios.get(cal1Url);
const cal2Data = await axios.get(cal2Url);
const promises = calendars.map((calendar) => {
return axios.get(calendar.url)
.then((response) => {
return {
data: response.data,
prefix: calendar.prefix,
};
})
.catch((error) => {
console.error(error);
return null;
});
});
const results = await Promise.all(promises);
// Filter out any failed requests
const validResults = results.filter((result) => result !== null);
// Parse calendar data
const cal1 = ical.parseICS(cal1Data.data);
const cal2 = ical.parseICS(cal2Data.data);
const mergedCal = [];
// Merge calendars
Object.keys(cal1).forEach((key) => {
let event = cal1[key];
mergedCal.push({
start: event.start,
end: event.end,
summary: `${cal1Prefix} ${event.summary}`,
validResults.forEach((result) => {
const calendar = ical.parseICS(result.data);
Object.keys(calendar).forEach((key) => {
const event = calendar[key];
mergedCal.push({
start: event.start,
end: event.end,
summary: `${result.prefix} ${event.summary}`,
});
});
});
Object.keys(cal2).forEach((key) => {
let event = cal2[key];
mergedCal.push({
start: event.start,
end: event.end,
summary: `${cal2Prefix} ${event.summary}`,
});
});
// Save merged calendar to file
const filename = `merged-${Date.now()}.ics`;
@ -63,6 +73,7 @@ END:VEVENT
icalString += `END:VCALENDAR`;
fs.writeFileSync(filename, icalString);
// Generate a unique URL for the merged calendar
const mergedCalendarUrl = `${req.protocol}://${req.get('host')}/${filename}`;