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

stills

v25.9.2

Published

A stills and GIF bot

Downloads

35

Readme

What is this?

A Frame

A small library to help you create a stills generator.

Dependencies

You're going to need:

  1. brew: https://brew.sh/
  2. imagemagick: brew install imagemagick
  3. ffmpeg: brew install ffmpeg

Setup

npm install stills --save

Usage

const {
  sources,
  content,
  filters,
  destinations,
  validators,
  generate,
  taggers
} = require('stills');
const { resolve } = require('path');

const config = {
  source: new sources.S3({
    accessKeyId: S3_ACCESS_KEY_ID,
    secretAccessKey: S3_SECRET_ACCESS_KEY,
    bucket: S3_BUCKET
  }),
  content: new content.Still(),
  filters: [
    new filters.Captions({
      folder: resolve('./captions')
    })
  ],
  validators: [new validators.FaceDetection()],
  getPostText: (filterOutput) => (filterOutput.captions || []).join('\n'),
  taggers: [
    new taggers.Episode(),
    new taggers.Static({
      tags: ['Hello']
    })
  ],
  destinations: [
    new destinations.Tumblr({
      consumerKey: TUMBLR_CONSUMER_KEY,
      consumerSecret: TUMBLR_CONSUMER_SECRET,
      token: TUMBLR_ACCESS_TOKEN_KEY,
      tokenSecret: TUMBLR_ACCESS_TOKEN_SECRET,
      blogName: TUMBLR_BLOG_NAME,
      tags: ['Hello']
    })
  ]
};

generate(config);

This will generate a random still from your S3 bucket, make sure at least one face appears in the image, add a caption from a random SRT file in the captions folder and then upload the result to Tumblr.

There are other options for source, content and validators. Keep readin'.

Generate multiple

In all likelihood you'll never use this, but if you're doing more advanced things, like posting multiple images in a single one run, or immediately reblogging the post with a different caption, you can use generateChain. This allowa you to execute multiple configs in a series. The configs can either be simple config objects like the standard case above, or a function that returns a config object.

await generateChain([
  firstConfig,
  (previousResult, allPreviousResults) => {
    return secondConfig;
  }
]);

The previousResult parameter passed in is the result of the previous run, which is essentially just whatever the filters return. Can sometimes come in handy. Example previousResult:

{
  "filters": {
    "captions": ["Welcome to Flavortown!", "Please stay a while"]
  }
}

Sources

Local folder

If you don't want to spend rack up your S3 bill while testing, you can point the generator at a local folder containing videos.

new stills.sources.Local({
  folder: resolve('./videos')
});

S3

As you saw in the example above, you can point the generator at an S3 bucket. It won't download the full video, as ffmpeg is capable of working with remote files.

new stills.sources.S3({
  accessKeyId: S3_ACCESS_KEY_ID,
  secretAccessKey: S3_SECRET_ACCESS_KEY,
  bucket: S3_BUCKET
});

Content

Stills

This one doesn't have any options. It's just:

new stills.content.Still();

GIFs

Most sites have some upper limit on GIF sizes, so you can adjust either the generated image width (default: 540), the duration (default: 2) or the frame-rate with fps (default: 12) to fit your needs.

new stills.content.Gif({
  width: 540,
  duration: 2,
  fps: 12
});

Filters

Captions

This filter supports reading random .srt files (movie subtitles) and .txt files (newline-separated lines) from a folder and applying them to either a still and the GIF.

new stills.filters.Captions({
  folder: resolve('./captions'),
  num: 1,
  isSequential: false,
  font: resolve('./fonts/maison.ttf')
  background: null,
});

The parameters:

  • folder (mandatory) is the location from which the subtitles files will be loaded.
  • num (default: 1) is only applicable to GIFs; it determines how many captions to apply, distributed evenly based on the GIF duration.
  • isSequential (default: false) is relevant when num > 1, determines whether the randomly picked captions are be sequential.
  • font (default: null) is a path to a font file, will use Arial if nothing is provided.
  • background (default: null) is an optional hex rgba color that will be added under the text, will use a text drop-shadow if nothing is provided.

Glitch

Destroys your content by mangling random bytes (default: 300).

new stills.filters.Glitch({
  bytes: 300
});

Distortion

Stretches your image; for a still, it will immediately apply the stretch, for a GIF, it will increasingly apply the transformation during the course of the animation.

widthFactor and heightFactor should be 0-1; the higher the number, the more it streches the image in that direction.

new stills.filters.Distortion({
  heightFactor: 0.6
  widthFactor: 0
});

Face zoom

Only works with GIFs! Detect a face from the last frame and zooms towards it throughout the GIF. If it can't find a face or if you give it a still image, it does nothing.

new stills.filters.FaceZoom({
  startPosition: 0.5,
  lastFrameDelayMs: null
});

By default it starts zooming towards the face half-way through the GIF, but you can adjust that using startPosition (0-1). You can also add a delay (in ms) to the last zoomed in frame with lastFrameDelayMs (default: null)

Melt

Applies a "max" between frames in your image, essentially leading it towards blacks and making it look like it's melting. No options.

new stills.filters.Melt();

Twin Peaks Sheriff's Station

If you watched Twin Peaks - The Return, you might be able to guess what this does. If not, I guess just try it and see what happens.

new stills.filters.Station();

Shuffle

Shuffle the frames in a GIF.

new stills.filters.Shuffle();

Stutter

Stutter a bunch of frames in a GIF. Turns normal frames like this:

1 2 3 4 5 6 7 8 9

to this:

1 2 3 4 3 4 3 4 9

new stills.filters.Stutter({
  startFrame: null,
  numFrames: 6,
  stutterLength: 2,
  stutterDelay: null
});
  • startFrame: where to start stuttering. Picks a random frame if null.
  • numFrames: number of frames to stutter for / replace with stutter.
  • stutterLength: number of frames to repeat. The above example with 3 would look like "1 2 3 4 5 3 4 5 8 9"
  • stutterDelay: delay of the stuttered frame in ms. Will just use the original delay if null.

Taggers

Taggers help assemble the list of tags that are added to posts when sent to destinations.

Episode

new taggers.Episode();

Passes the name of the input file (from your source) as a tag.

Static

new taggers.Static({
  tags: ['Hello']
});

Simply passes along whatever you specify in tags.

Captions

new taggers.Captions();

If you've used the caption filter, it'll extract nouns and other tag-friendly words to use as tags.

Destinations

Tumblr

What it says on the box.

new stills.destinations.Tumblr({
  consumerKey: TUMBLR_CONSUMER_KEY,
  consumerSecret: TUMBLR_CONSUMER_SECRET,
  token: TUMBLR_ACCESS_TOKEN_KEY,
  tokenSecret: TUMBLR_ACCESS_TOKEN_SECRET,
  blogName: TUMBLR_BLOG_NAME,
  tags: ['Hello'],
  isIncludeText: true,
  },
});

The name of the video file is automatically added as a tag to the post, but you can also provide additional ones with the tags parameter (default: []).

Post text captions

You can add some text to the Tumblr if you set isIncludeText to true in each individual destination, and pass in a getPostText method into the generate call. An object will be passed into getPostText method with the output from the various filters that are applied (key is the name of the filter).

Validators

When a validator fails, it deletes the generated image and creates another one to try again. It does this a maximum of 10 times, and then gives up and posts whatever.

Face detection

Using Tensorflow, makes sure there's at least one face in the image.

new stills.validators.FaceDetection();

Bye!

If you'd like to provide any additional plugins (like sources or filters), please fork the repo and open a PR!