• Stars
    star
    118
  • Rank 299,135 (Top 6 %)
  • Language
    JavaScript
  • License
    Apache License 2.0
  • Created over 4 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

NodeJS class for parsing iCalendar/ICS files

node-ical

Build NPM version Downloads Contributors License Donate GitHub stars

A minimal iCalendar/ICS (http://tools.ietf.org/html/rfc5545) parser for Node.js. This module is a direct fork of the ical.js module by Peter Braden (https://github.com/peterbraden/ical.js) which is primarily targeted for parsing iCalender/ICS files in a pure JavaScript environment. (ex. within the browser itself) This node-ical module however, primarily targets Node.js use and allows for more flexible APIs and interactions within a Node environment. (like filesystem access!)

Install

node-ical is availble on npm:

npm install node-ical

API

The API has now been broken into three sections:

sync provides synchronous API functions. These are easy to use but can block the event loop and are not recommended for applications that need to serve content or handle events.

async provides proper asynchronous support for iCal parsing. All functions will either return a promise for async/await or use a callback if one is provided.

autodetect provides a mix of both for backwards compatibility with older node-ical applications.

All API functions are documented using JSDoc in the node-ical.js file. This allows for IDE hinting!

sync

// import ical
const ical = require('node-ical');

// use the sync function parseFile() to parse this ics file
const events = ical.sync.parseFile('example-calendar.ics');
// loop through events and log them
for (const event of Object.values(events)) {
    console.log(
        'Summary: ' + event.summary +
        '\nDescription: ' + event.description +
        '\nStart Date: ' + event.start.toISOString() +
        '\n'
    );
};

// or just parse some iCalendar data directly
const directEvents = ical.sync.parseICS(`
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
SUMMARY:Hey look! An example event!
DTSTART;TZID=America/New_York:20130802T103400
DTEND;TZID=America/New_York:20130802T110400
LOCATION:1000 Broadway Ave.\, Brooklyn
DESCRIPTION: Do something in NY.
STATUS:CONFIRMED
UID:7014-1567468800-1567555199@[email protected]
END:VEVENT
END:VCALENDAR
`);
// log the ids of these events
console.log(Object.keys(directEvents));

async

// import ical
const ical = require('node-ical');

// do stuff in an async function
;(async () => {
    // load and parse this file without blocking the event loop
    const events = await ical.async.parseFile('example-calendar.ics');

    // you can also use the async lib to download and parse iCal from the web
    const webEvents = await ical.async.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics');
    // also you can pass options to axios.get() (optional though!)
    const headerWebEvents = await ical.async.fromURL(
        'http://lanyrd.com/topics/nodejs/nodejs.ics',
        { headers: { 'User-Agent': 'API-Example / 1.0' } }
    );

    // parse iCal data without blocking the main loop for extra-large events
    const directEvents = await ical.async.parseICS(`
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
SUMMARY:Hey look! An example event!
DTSTART;TZID=America/New_York:20130802T103400
DTEND;TZID=America/New_York:20130802T110400
DESCRIPTION: Do something in NY.
UID:7014-1567468800-1567555199@[email protected]
END:VEVENT
END:VCALENDAR
    `);
})()
    .catch(console.error.bind());

// old fashioned callbacks cause why not

// parse a file with a callback
ical.async.parseFile('example-calendar.ics', function(err, data) {
    if (err) {
        console.error(err);
        process.exit(1);
    }
    console.log(data);
});

// or a URL
ical.async.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', function(err, data) { console.log(data); });

// or directly
ical.async.parseICS(`
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
SUMMARY:Hey look! An example event!
DTSTART;TZID=America/New_York:20130802T103400
DTEND;TZID=America/New_York:20130802T110400
DESCRIPTION: Do something in NY.
UID:7014-1567468800-1567555199@[email protected]
END:VEVENT
END:VCALENDAR
`, function(err, data) { console.log(data); });

autodetect

These are the old API examples, which still work and will be converted to the new API automatically. Functions with callbacks provided will also have better performance over the older versions even if they use the old API.

Parses a string with ICS content in sync. This can block the event loop on big files.

const ical = require('node-ical');
ical.parseICS(str);

Parses a string with ICS content in async to prevent the event loop from being blocked.

const ical = require('node-ical');
ical.parseICS(str, function(err, data) {
    if (err) console.log(err);
    console.log(data);
});

Parses a string with an ICS file in sync. This can block the event loop on big files.

const ical = require('node-ical');
const data = ical.parseFile(filename);

Parses a string with an ICS file in async to prevent event loop from being blocked.

const ical = require('node-ical');
const data = ical.parseFile(filename, function(err, data) {
    if (err) console.log(err);
    console.log(data);
});

Reads in the specified iCal file from the URL, parses it and returns the parsed data.

const ical = require('node-ical');
ical.fromURL(url, options, function(err, data) {
    if (err) console.log(err);
    console.log(data);
});

Use the axios library to get the specified URL (opts gets passed on to the axios.get() call), and call the function with the result. (either an error or the data)

Example 1 - Print list of upcoming node conferences (see example.js) (parses the file synchronous)

const ical = require('node-ical');
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function (err, data) {
    for (let k in data) {
        if (data.hasOwnProperty(k)) {
            const ev = data[k];
            if (data[k].type == 'VEVENT') {
                console.log(`${ev.summary} is in ${ev.location} on the ${ev.start.getDate()} of ${months[ev.start.getMonth()]} at ${ev.start.toLocaleTimeString('en-GB')}`);
            }
        }
    }
});

Recurrence rule (RRule)

Recurrence rule will be created with timezone if present in DTSTART

To get correct date from recurrences in the recurrence rule, you need to take the original timezone and your local timezone into account

If no timezone were provided when recurrence rule were created, recurrence dates should take original start timezoneoffset and the current dates timezoneoffset into account

const ical = require('node-ical');
const moment = require('moment-timezone');

ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function (err, data) {
    for (let k in data) {
        if (!Object.prototype.hasOwnProperty.call(data, k)) continue;

        const event = data[k];
        if (event.type !== 'VEVENT' || !event.rrule) continue;
        
        const dates = event.rrule.between(new Date(2021, 0, 1, 0, 0, 0, 0), new Date(2021, 11, 31, 0, 0, 0, 0))
        if (dates.length === 0) continue;

        console.log('Summary:', event.summary);
        console.log('Original start:', event.start);
        console.log('RRule start:', `${event.rrule.origOptions.dtstart} [${event.rrule.origOptions.tzid}]`)

        dates.forEach(date => {
            let newDate
            if (event.rrule.origOptions.tzid) {
                // tzid present (calculate offset from recurrence start)
                const dateTimezone = moment.tz.zone('UTC')
                const localTimezone = moment.tz.guess()
                const tz = event.rrule.origOptions.tzid === localTimezone ? event.rrule.origOptions.tzid : localTimezone
                const timezone = moment.tz.zone(tz)
                const offset = timezone.utcOffset(date) - dateTimezone.utcOffset(date)
                newDate = moment(date).add(offset, 'minutes').toDate()
            } else {
                // tzid not present (calculate offset from original start)
                newDate = new Date(date.setHours(date.getHours() - ((event.start.getTimezoneOffset() - date.getTimezoneOffset()) / 60)))
            }
            const start = moment(newDate)
            console.log('Recurrence start:', start)
        })

        console.log('-----------------------------------------------------------------------------------------');
    }
});

More Repositories

1

RaspberryMatic

🏠 A feature-rich but lightweight, buildroot-based Linux operating system alternative for your CloudFree CCU3/ELV-Charly 'homematicIP CCU' IoT smarthome central. Running as a pure virtual appliance (ProxmoxVE, Home Assistant, LXC, Docker/OCI, Kubernetes/K8s, etc.) on a dedicated embedded device (RaspberryPi, etc.) or generic x86/ARM hardware.
JavaScript
1,518
star
2

node-unifi

NodeJS class for querying/controlling a UniFi-Controller (UDM-Pro, UDM-SE, UDM, UDR, UDW, CloudKey Gen1/Gen2) from Ubiquiti (www.ui.com)
JavaScript
138
star
3

amissl

🔐 AmiSSL is the AmigaOS/MorphOS/AROS port of OpenSSL. It wraps the full functionality of OpenSSL into a full-fledged Amiga shared library that makes it possible for Amiga applications to use the full OpenSSL API through a standard Amiga shared library interface (e.g. web browsers wanting to support HTTPS, etc.)...
C
86
star
4

cuxd

CUx-Daemon – a universal interface between the HomeMatic CCU logic layer (ReGaHSS) and third-party (EnOcean, M-Bus, 1-Wire, ArtDMX, etc.) external and virtual devices.
C
65
star
5

yam

📬 YAM (short for 'Yet Another Mailer') is a MIME-compliant open-source Internet email client written for Amiga-based computer systems (AmigaOS4, AmigaOS3, MorphOS, AROS). It supports POP3, SMTP, TLSv1/SSLv3 connection security, multiple users, multiple identities, PGPv2/v5 encryption, unlimited hierarchical folders, an ARexx interface, etc...
C
61
star
6

thinRoot

thinRoot is a buildroot (https://buildroot.org/) powered operating system environment to create lightweight user-defined kiosk systems or ThinClients (e.g. using x86 hardware, RaspberryPi, ASUS Tinkerboard, etc.) to smoothly connect to server-based desktop environments via ThinLinc, RDP, SPICE@ProxmoxVE, VNC or to create a simply web-kiosk.
Python
51
star
7

libcodesets

codesets.library is an AmigaOS shared library to handle different codesets (i.e. ISO-8859-1, UTF-8, etc.) and their respective conversions. It provides public functions for applications to deal with multiple codesets and convert them properly.
C
18
star
8

lrecog

A neuronal network based image recognition application that aims on the automatic recognition of tree species according to available images of the leaves of each species. With help of this application botanists can then identify different species...
Java
14
star
9

magicmenu

MagicMenu is a menu enhancer for AmigaOS oriented operating systems. It allows to override the default look&feel of menus presented in AmigaOS and provides a user configurable way to show nice looking menus instead of the default ones...
C
12
star
10

vxext_fs

Linux kernel module for VxWorks extended DOS filesystem support.
C
9
star
11

node-panasonic-viera

NodeJS class to query and control Panasonic™ Viera™ Smart-TVs
JavaScript
8
star
12

libopenurl

A library (openurl.library) and tools for opening an application in accordance to a supplied URL. It is explicitly designed to be used by AmigaOS compatible operating systems such as AmigaOS3, AmigaOS4, MorphOS or AROS.
C
7
star
13

occu

Tcl
7
star
14

amide

AmIDE - Amiga Integrated Development Environment is a modern MUI based IDE system that should make the Amiga developer able to use his favourite Compiler system with a modern looking GUI System with features like filetype handling, Build/Make, TextEd
C
6
star
15

newsrog

NewsRog is the most powerful newsreader available for the Amiga platform. Combining a Magic User Interface frontend, an OOP approach and its overwhelming list of features, it provides the best experience even to the most demanding Usenetters.
C
6
star
16

anfs

An implementation of the Network File System protocol (NFS) for AmigaOS-based operating systems. This project is open source and based on the formerly known 'ch_nfs' NFS client and the "nfsd" NFS server implementation originally targeted for AmiTCP...
C
5
star
17

jens-maus

Personal Page Repo
4
star
18

dessolver

A Java-based Ordinary Differential Equation (ODE) System Solver Application...
Java
4
star
19

betterlayers

A replacement library which aim in replacing the default AmigaOS "layers.library" to more efficently manage layers operations on modern AmigaOS operating systems. It comes with some advanced layers techniques to speed up operations...
C
4
star
20

occu-test

Automated System Tests of "ReGaHss" - the HomeMatic (O)CCU "Logic Layer" Engine...
JavaScript
3
star
21

librtdebug

librtdebug is a comprehensive runtime debugging library which allows developers to insert predefined macros within their own source code and track the 'runtime' of their applications via standardized textual output...
C++
2
star
22

xmlrpcpp

Fork of unmaintained http://xmlrpcpp.sf.net with patches and certain fixes applied
C++
1
star