1.4.0 • Published 8 months ago

mdfind-node v1.4.0

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

mdfind-node šŸ”

Supercharged macOS file and metadata search using mdfind for Node.js! ✨

npm version License: ISC Lint

A powerful Node.js wrapper for macOS's Spotlight search (mdfind), bringing system-level search capabilities to your JavaScript applications.

✨ Features

  • šŸš€ Full Spotlight Integration - Access all macOS Spotlight search capabilities
  • šŸ”„ Smart Query Builder - Type-safe, fluent API for building complex searches
  • šŸ”„ Live Search Support - Real-time file monitoring and updates
  • šŸ“¦ Batch Operations - Run multiple searches in parallel or sequence
  • šŸ“ Rich Metadata - Access EXIF, XMP, and system metadata
  • šŸ’Ŗ Type-Safe - Full TypeScript support with detailed types
  • šŸ› ļø Configurable - Extensive options for fine-tuned control
  • 🌳 Type Trees - Support for content type hierarchies
  • šŸŽØ Specialized Methods - Purpose-built methods for common file types

šŸ“„ Documentation

šŸ“„ Installation

# Using pnpm (recommended)
pnpm add mdfind-node

# Using npm
npm install mdfind-node

# Using yarn
yarn add mdfind-node

# Using bun
bun add mdfind-node

šŸš€ Quick Start

import { QueryBuilder } from 'mdfind-node'

// Find recent Markdown files
const docs = await new QueryBuilder()
  .isMarkdown()
  .modifiedAfter(new Date('2024-01-01'))
  .inDirectory('~/Documents')
  .execute()

// Find high-resolution photos
const photos = await new QueryBuilder()
  .contentType('public.image')
  .minImageDimensions(3000, 2000)
  .hasGPS()
  .inDirectory('~/Pictures')
  .execute()

// Find large media files
const videos = await new QueryBuilder()
  .isAudiovisual()
  .largerThan(100 * 1024 * 1024) // > 100MB
  .inDirectory('~/Movies')
  .execute()

šŸŽÆ Key Features

šŸ” Smart Query Builder

The QueryBuilder provides a fluent, type-safe API for building complex searches:

import { QueryBuilder } from 'mdfind-node'

// Find documents by author
const authorDocs = await new QueryBuilder()
  .contentType('com.adobe.pdf')
  .author('John Doe')
  .createdAfter(new Date('2024-01-01'))
  .inDirectory('~/Documents')
  .execute()

// Find photos from a specific camera
const cameraPhotos = await new QueryBuilder()
  .contentType('public.image')
  .takenWith('iPhone 14 Pro')
  .hasGPS()
  .inDirectory('~/Pictures')
  .execute()

// Find code files with specific content
const codeFiles = await new QueryBuilder()
  .isText()
  .extension('ts')
  .containing('QueryBuilder')
  .modifiedAfter(new Date('2024-01-01'))
  .execute()

// Combine conditions with OR
const mediaFiles = await new QueryBuilder()
  .useOperator('||')
  .extension('mp4')
  .extension('mov')
  .extension('avi')
  .largerThan(50 * 1024 * 1024)
  .execute()

šŸ”„ Live Search

import { QueryBuilder, mdfindLive } from 'mdfind-node'

// Create a query to watch for new PDFs
const query = new QueryBuilder().isPDF().inDirectory('~/Downloads').toString()

const search = mdfindLive(
  query,
  { reprint: true },
  {
    onResult: paths => console.log('New matches:', paths),
    onError: error => console.error('Search error:', error),
    onEnd: () => console.log('Search ended')
  }
)

šŸ“¦ Batch Operations

import { QueryBuilder } from 'mdfind-node'
import { batchSearch } from 'mdfind-node'

// Create multiple queries
const searches = [
  {
    query: new QueryBuilder().contentType('public.image').minImageDimensions(1920, 1080).toString(),
    options: { onlyInDirectory: '~/Pictures' }
  },
  {
    query: new QueryBuilder()
      .contentType('com.adobe.pdf')
      .modifiedAfter(new Date('2024-01-01'))
      .toString(),
    options: { onlyInDirectory: '~/Documents' }
  }
]

// Run them in parallel
const results = await batchSearch(searches)

// Or use utility functions for common patterns
import { mdfindMultiDirectory, mdfindMultiQuery } from 'mdfind-node'

// Search same query across multiple directories
const directoryResults = await mdfindMultiDirectory(
  new QueryBuilder().contentType('public.image').toString(),
  ['~/Pictures', '~/Documents']
)

// Search multiple queries in one directory
const queryResults = await mdfindMultiQuery(
  [
    new QueryBuilder().contentType('public.image').toString(),
    new QueryBuilder().contentType('com.adobe.pdf').toString()
  ],
  '~/Documents'
)

šŸ“ Extended Metadata

import { getExtendedMetadata } from 'mdfind-node'

const metadata = await getExtendedMetadata('photo.jpg')
console.log('Basic:', metadata.basic)
console.log('EXIF:', metadata.exif)
console.log('XMP:', metadata.xmp)

šŸŽÆ Specialized Search Methods

The QueryBuilder includes specialized methods for common file types:

import { QueryBuilder } from 'mdfind-node'

// Find text files
const textFiles = await new QueryBuilder().isText().modifiedAfter(new Date('2024-01-01')).execute()

// Find media files
const mediaFiles = await new QueryBuilder()
  .isAudiovisual()
  .largerThan(10 * 1024 * 1024)
  .execute()

// Find applications
const apps = await new QueryBuilder().isApplication().inDirectory('/Applications').execute()

// Find configuration files
const configs = await new QueryBuilder().isPlist().inDirectory('~/Library/Preferences').execute()

// Find development files
const devFiles = await new QueryBuilder()
  .useOperator('||')
  .isText()
  .isMarkdown()
  .isJSON()
  .isYAML()
  .inDirectory(process.cwd())
  .execute()

šŸ” Attribute Discovery

Spotlight attributes can be complex to work with. This library provides utilities to help you discover and understand available attributes:

import { discoverAttributes, searchAttributes, getContentTypes } from 'mdfind-node'

// Get all available attributes for a specific file
const fileAttributes = discoverAttributes('path/to/file.jpg')

// Search for attributes by keyword
const imageAttrs = searchAttributes('image')
console.log(imageAttrs)
// [
//   {
//     name: 'kMDItemPixelHeight',
//     description: 'Height of the image in pixels',
//     type: 'number',
//     example: 1080,
//     category: 'image'
//   },
//   ...
// ]

// Get all known content types
const contentTypes = getContentTypes()
console.log(contentTypes['public.image']) // 'Image files (JPEG, PNG, etc.)'

// Get attributes by category
const locationAttrs = getAttributesByCategory('location')

Content Type Trees

Files in macOS are organized in a type hierarchy. For example:

public.item
└── public.content
    ā”œā”€ā”€ public.text
    │   ā”œā”€ā”€ public.plain-text
    │   └── net.daringfireball.markdown
    └── public.audiovisual-content
        ā”œā”€ā”€ public.audio
        └── public.movie

Common Content Types

Basic Types:

  • public.item - Base type for all items
  • public.content - Base type for all content
  • public.text - Text-based content
  • public.composite-content - Content with multiple parts

Documents:

  • public.plain-text - Plain text files
  • public.rtf - Rich Text Format documents
  • com.adobe.pdf - Adobe PDF Document
  • net.daringfireball.markdown - Markdown Document

Media:

  • public.image - Image files (JPEG, PNG, etc.)
  • public.audio - Audio files (MP3, WAV, etc.)
  • public.movie - Video files (MP4, MOV, etc.)
  • public.audiovisual-content - Audio/Visual content

Code:

  • public.source-code - Source Code File
  • public.shell-script - Shell Script
  • public.json - JSON File
  • public.yaml - YAML File

System:

  • com.apple.bundle - Generic Bundle
  • com.apple.application - Generic Application
  • com.apple.property-list - Property List (plist)

Common Attributes

  • kMDItemContentType - The type of content
  • kMDItemContentTypeTree - The content type hierarchy
  • kMDItemDisplayName - The display name of the file
  • kMDItemFSName - The filename on disk
  • kMDItemContentCreationDate - When the file was created
  • kMDItemContentModificationDate - When the file was last modified
  • kMDItemPixelHeight - Height of the image in pixels
  • kMDItemPixelWidth - Width of the image in pixels
  • kMDItemLatitude - GPS latitude where photo/video was taken
  • kMDItemLongitude - GPS longitude where photo/video was taken

šŸ‘©ā€šŸ’» Development

# Install dependencies
pnpm install

# Development build with watch mode
pnpm dev

# Production build
pnpm build

# Run tests
pnpm test

# Run examples
pnpm examples:basic
pnpm examples:advanced
pnpm examples:query-builder
pnpm examples:live-search
pnpm examples:metadata
pnpm examples:batch
pnpm examples:discover
pnpm examples:content-types

šŸ“„ License

ISC Ā© Matthew Herod


1.4.0

8 months ago

1.3.0

8 months ago

1.2.0

8 months ago

1.1.0

8 months ago

1.0.0

8 months ago