npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

zsv

v1.1.0

Published

Parse Zoom Meeting CSVs with Ease

Downloads

7

Readme

Zoom Meeting CSV Parser

A simple Zoom meeting and webinar csv parser.

Basic Usage

import {
  zoom,

  // transformations
  camelCase,
  compact,
  deDupeByName,
  deDupeByIP,
  flatten,
  group,
  minutesInMeeting,
  pluck,
  toArray,
} from 'zsv';

// transformations are optional, you may supply your own or none at all
const [hosts, participants] = await zoom('example.csv', deDupeByName, camelCase, flatten);

// Do stuff with your hosts and participants
console.log(hosts);
console.log(participants);

Unaltered Meeting Participant

{
  participant: "archer",
  device: "Mac",
  ip_address: "192.168.241.19",
  location: "Milpitas (US )",
  network_type: "Wifi",
  join_time: "06:00 AM",
  leave_time: "06:03 AM",
  version: "3.5.64836.0908",
  audio__receiving_bitrate: "79 kbps",
  audio__sending_bitrate: "-",
  audio__receiving_latency: "77 ms",
  audio__sending_latency: "-",
  audio__receiving_jitter: "8 ms",
  audio__sending_jitter: "-",
  audio__receiving_packet_loss_avg_max: "0.15 %(0.65 %)",
  audio__sending_packet_loss_avg_max: "-(-)",
  video__receiving_bitrate: "-",
  video__sending_bitrate: "-",
  video__receiving_latency: "77 ms",
  video__sending_latency: "-",
  video__receiving_jitter: "9 ms",
  video__sending_jitter: "-",
  video__receiving_packet_loss_avg_max: "-(-)",
  video__sending_packet_loss_avg_max: "-(-)",
  video__receiving_resolution: "-",
  video__sending_resolution: "-",
  video__receiving_frame_rate: "-",
  video__sending_frame_rate: "-",
  screen_sharing__receiving_bitrate: "155 kbps",
  screen_sharing__sending_bitrate: "155 kbps",
  screen_sharing__receiving_latency: "78 ms",
  screen_sharing__sending_latency: "78 ms",
  screen_sharing__receiving_jitter: "11 ms",
  screen_sharing__sending_jitter: "9 ms",
  screen_sharing__receiving_packet_loss_avg_max: "-(-)",
  screen_sharing__sending_packet_loss_avg_max: "-(-)",
  screen_sharing__receiving_resolution: "2560*1440",
  screen_sharing__sending_resolution: "2560*1440",
  screen_sharing__receiving_frame_rate: "16 fps",
  screen_sharing__sending_frame_rate: "19 fps",
  zoom_min_cpu_usage: "4 %",
  zoom_avg_cpu_usage: "8 %",
  zoom_max_cpu_usage: "11 %",
  system_max_cpu_usage: "23 %"
}

Transformations

There are a number of included transformations that alter the structure of participant and host objects.

camelCase

Transforms fields to camel case

await zoom('meeting.csv', camelCase);

Output:

{
  participant: "archer",
  device: "Mac",
  ipAddress: "192.168.241.19",
  location: "Milpitas (US )",
  networkType: "Wifi",
  joinTime: "06:00 AM",
  leaveTime: "06:03 AM",
  ...
}

compact

Removes null and undefined values from webinar csv's

await zoom('webinar.csv', compact);

deDupeByName

Merge participants based on name (participant). May contain arrays of values.

await zoom('meeting.csv', deDupeByName);

Output:

{
  participant: "archer",
  device: "Mac",
  ip_address: "192.168.241.19",
  location: "Milpitas (US )",
  network_type: "Wifi",
  join_time: ["06:00 AM", "06:11 AM"],
  leave_time: ["06:03 AM", "06:37 AM"],
  ...
}

deDupeByIP

Merge participants based on IP. May contain arrays of values.

await zoom('meeting.csv', deDupeByIP);

Output:

{
  participant: ["archer", "Archer"],
  device: "Mac",
  ip_address: "192.168.241.19",
  location: "Milpitas (US )",
  network_type: "Wifi",
  join_time: ["06:00 AM", "06:11 AM"],
  leave_time: ["06:03 AM", "06:37 AM"],
  ...
}

flatten

Flatten array values after deDuping.

await zoom('meeting.csv', deDupeByIP, flatten);

Output:

{
  participant: "archer",
  device: "Mac",
  ip_address: "192.168.241.19",
  location: "Milpitas (US )",
  network_type: "Wifi",
  join_time: "06:00 AM",
  leave_time: "06:37 AM",
  ...
}

group

Group creates objects from similar field names, such as:

{
  screen_sharing__receiving_bitrate: "155 kbps",
  screen_sharing__sending_bitrate: "155 kbps"
}
await zoom('meeting.csv', group);

Output:

{
  screen_sharing: {
    receiving_bitrate: "155 kbps",
    sending_bitrate: "155 kbps",
    receiving_latency: "78 ms",
    sending_latency: "78 ms",
    receiving_jitter: "9 ms",
    sending_jitter: "9 ms",
    receiving_packet_loss_avg_max: "-(-)",
    sending_packet_loss_avg_max: "-(-)",
    receiving_resolution: "2560*1440",
    sending_resolution: "2560*1440",
    receiving_frame_rate: "16 fps",
    sending_frame_rate: "16 fps"
  },
  ...
}

minutesInMeeting

Attempts to calculate participant time spent in the meeting.
Adds new property minutes_in_meeting by default, or minutesInMeeting if camelCase transform has been utilized.

await zoom('meeting.csv', minutesInMeeting);

Output:

{
  participant: "archer",
  device: "Mac",
  ip_address: "192.168.241.19",
  location: "Milpitas (US )",
  ...
  minutes_in_meeting: 3
}

pluck

Pluck takes a list of field names to create a new object.

await zoom(
  'meeting.csv',
  pluck('participant', 'device', 'location', ['ip_address', 'network_type']),
);

Output:

{
  participant: "archer",
  ip_address: "192.168.241.19",
  device: "Mac",
  network_type: "Wifi",
  location: "Milpitas (US )"
}

toArray

Creates an array of key value pairs.

Output:

[
  [ 'participant', 'archer' ],
  [ 'device', 'Mac' ],
  [ 'ip_address', '192.168.241.19' ],
  [ 'location', 'Milpitas (US )' ],
  [ 'network_type', 'Wifi' ],
  [ 'join_time', '06:00 AM' ],
  [ 'leave_time', '06:03 AM' ],
  ...
]

Transforming with group before toArray will create multiple nested arrays.

[
  ['participant', 'archer'],
  [
    'audio',
    [
      ['receiving_bitrate', '79 kbps'],
      ['sending_bitrate', '-'],
      ['receiving_latency', '77 ms'],
      ['sending_latency', '-'],
      ['receiving_jitter', '8 ms'],
      ['sending_jitter', '-'],
      ['receiving_packet_loss_avg_max', '0.15 %(0.65 %)'],
      ['sending_packet_loss_avg_max', '-(-)'],
    ],
  ],
];

Custom Transforms

You may create your own custom transformations by supplying a function with the following interfaces:

function doStuff(participants) {
  // do stuff with the participants array
  for (const participant of participants) {
    // things are happening
  }

  // return array of participants
  return participants;
}

or:

function transform(field, value, participant) {
  // do stuff with participant

  participant[field] = `modified ${value}`;

  // return the modified participant
  return participant;
}

Caveats

Pluck attempts to transform both host and participant objects.
If you plan to work with the host object it might behoove you to utilize pluck after you receive the data objects.

const [hosts, participants] = await zoom('meeting.csv');
const plucked = pluck('participant', 'location')(participants);