The script bundles several .ics files into one .csv file
The functions:
// upload and list files with filesizeletfileInput=document.getElementById('fileInput');letfileList=document.querySelector('.file-list');fileInput.addEventListener('change',function(){letfiles=fileInput.files;for(leti=0;i<files.length;i++){letfile=files[i];letlistItem=document.createElement('div');listItem.classList.add('file-item');leticon=document.createElement('i');icon.classList.add('calendar-icon');letname=document.createElement('div');name.classList.add('file-name');name.innerText=file.name;letsize=document.createElement('div');size.classList.add('file-size');size.innerText=formatBytes(file.size);listItem.appendChild(icon);listItem.appendChild(name);listItem.appendChild(size);fileList.appendChild(listItem);}});functionformatBytes(bytes,decimals=2){if(bytes===0)return'0 Bytes';constk=1024;constdm=decimals<0 ? 0 : decimals;constsizes=['Bytes','KB','MB','GB','TB','PB','EB','ZB','YB'];consti=Math.floor(Math.log(bytes)/Math.log(k));returnparseFloat((bytes/Math.pow(k,i)).toFixed(dm))+' '+sizes[i];}// iCalMerge2csvfunctionmergeAndExport(){constinputElements=document.getElementById("fileInput").files;constcalendarEvents=[];for(leti=0;i<inputElements.length;i++){constreader=newFileReader();reader.onload=function(event){constfileContent=event.target.result;constevents=parseICal(fileContent);calendarEvents.push(...events);if(i===inputElements.length-1){exportAsCSV(calendarEvents);}};reader.readAsText(inputElements[i]);}}functionparseICal(fileContent){// Split the file content by line breaksconstlines=fileContent.trim().split("\n");// Find all VEVENT blocksconstveventBlocks=[];letcurrentBlock=null;for(leti=0;i<lines.length;i++){constline=lines[i].trim();if(line==="BEGIN:VEVENT"){currentBlock=[];}elseif(line==="END:VEVENT"){veventBlocks.push(currentBlock);currentBlock=null;}elseif(currentBlock!==null){currentBlock.push(line);}}// Parse each VEVENT block into a calendar event objectconstcalendarEvents=[];for(leti=0;i<veventBlocks.length;i++){constveventBlock=veventBlocks[i];constcalendarEvent={};for(letj=0;j<veventBlock.length;j++){constline=veventBlock[j];const[key,value]=line.split(":");if(key==="SUMMARY"){calendarEvent.summary=value;}elseif(key==="DTSTART"){calendarEvent.start=newDate(value);}elseif(key==="DTEND"){calendarEvent.end=newDate(value);}elseif(key==="LOCATION"){calendarEvent.location=value;}elseif(key==="DESCRIPTION"){calendarEvent.description=value;}}calendarEvents.push(calendarEvent);}returncalendarEvents;}functionexportAsCSV(calendarEvents){constcsvContent="data:text/csv;charset=utf-8,"+convertToCSV(calendarEvents);constencodedUri=encodeURI(csvContent);constlink=document.createElement("a");link.setAttribute("href",encodedUri);link.setAttribute("download","merged_events.csv");document.body.appendChild(link);// Required for Firefoxlink.click();}functionconvertToCSV(calendarEvents){constlines=[];lines.push("Summary,Start Time,End Time,Location,Description");for(leti=0;i<calendarEvents.length;i++){constevent=calendarEvents[i];conststartTime=event.start.toLocaleString();constendTime=event.end.toLocaleString();constsummary=event.summary||"";constlocation=event.location||"";constdescription=event.description||"";lines.push(`${summary},${startTime},${endTime},${location},${description}`);}returnlines.join("\n");}