mediasim

package module
v0.0.0-...-6c06906 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

README

Media Similarity (MediaSim)

mediasim
MediaSim is a CLI tool and Go library to calculate the similarity of images & videos.

⬇️ Installation

This app has versions for Windows, macOS, and Linux. Download the latest release that matches your computer architecture and operating system.

However, the recommended (and easiest) way to install MediaSim is using one of the following scripts; copy and paste the command below in the terminal, and the script will automatically detect and install the correct version of the app:

macOS & Linux
curl -fsSL https://vegidio.github.io/mediasim/install.sh | sh
Windows (PowerShell)
irm https://vegidio.github.io/mediasim/install.ps1 | iex

🖼️ Usage

You can use mediasim in two ways: as a command-line interface (CLI) tool or a Go library.

The CLI tool is a standalone application that can be used to compare the similarity between media files, while the library can be integrated into your own Go projects.

CLI

mediasim

Calculating the similarity score of two files
Run the command below in the terminal:
$ mediasim score <media1> <media2>
Comparing two or more files
Run the command below in the terminal:
$ mediasim files <media1> <media2> [<media3> ...]

Where:

  • files (mandatory): the path to the media files you want to compare. You must pass at least two files, separated by space.
Comparing multiple files in a directory
Run the command below in the terminal:
$ mediasim dir <directory> [-r] [--mt <media-type>]

Where:

  • directory (mandatory): the path to the directory where the media files are located.
  • -r (optional): recursively search for files in subdirectories to include in the comparison.
  • --mt (optional): the file types to be included in the comparison. You can choose between image, video, or all (default).
Renaming files based on similarity
Run the command below in the terminal:
$ mediasim rename <directory> [-r] [--mt <media-type>]

Where:

  • directory (mandatory): the path to the directory where the media files are located.
  • -r (optional): recursively search for files in subdirectories to include in the comparison.
  • --mt (optional): the file types to be included in the comparison. You can choose between image, video, or all (default).

Other parameters you can use:

  • -t (optional): the threshold for the similarity score; a value between 0–1, where 0 is completely different and 1 is identical. The default value is 0.8, which means only similarities of 80% or higher will be reported.
  • -o (optional): the output format; you can choose report (default) or, if you prefer a raw output, json or csv.
  • --ie (optional): ignores errors and continues the comparison even if some files are not valid.
  • --ff (optional): flips the frames vertically and horizontally during the comparison.
  • --fr (optional): rotates the frames in multiple angles during the comparison.

For the full list of parameters, type mediasim --help in the terminal.

🎞️ Supported media types

In its default configuration, the mediasim library supports media files with the following extensions:

  • Images: .bmp, .gif, .jpg (.jpeg), .png, .tiff, .webp
  • Videos: .avi, .mp4 (.m4v), .mkv, .mov, .webm

The CLI supports two additional image formats: .avif and .heic.

If you want to work with additional file extensions in the library, like those two above, you can use the functions AddImageType or AddVideoType before performing any similarity comparisons. This allows mediasim to include these file types during calculations.

When adding support for new media formats, it's essential to load a 3rd party library capable of decoding them. For example, to enable AVIF image comparison in mediasim, you could use a library like avif-go to do this:

import _ "github.com/vegidio/avif-go"
mediasim.AddImageType(".avif")

💣 Troubleshooting

Video Comparison Doesn't Work

If the comparison of videos is not working, it may be because you don't have FFmpeg working in your computer, which is required to extract frames from the video files.

When FFmpeg is not found, mediasim will try to automatically download and install it for you. Even though this will work in most cases, it may fail for unpredictable reasons.

The best option to have the video comparison working is to install FFmpeg yourself in your computer and make sure it is available in your PATH.

Video Comparison Is Taking Too Long

Comparing videos is inherently resource-intensive because it requires analyzing multiple frames from each video to get an accurate similarity score. For instance, comparing two 15-second videos requires roughly 250 times more CPU resources than comparing two images.

Therefore, if you have many videos to compare, especially long ones, the process may take a significant amount of time, and unfortunately, there is not much that can be done to speed it up.

"App Is Damaged/Blocked..." (Windows & macOS only)

For a couple of years now, Microsoft and Apple have required developers to join their "Developer Program" to gain the pretentious status of an identified developer 😛.

Translating to non-BS language, this means that if you’re not registered with them (i.e., paying the fee), you can’t freely distribute Windows or macOS software. Apps from unidentified developers will display a message saying the app is damaged or blocked and can’t be opened.

To bypass this, open the Terminal and run one of the commands below (depending on your operating system), replacing <path-to-app> with the correct path to where you’ve installed the app:

  • Windows: Unblock-File -Path <path-to-app>
  • macOS: xattr -d com.apple.quarantine <path-to-app>

🛠️ Build

Dependencies

To build this project, you will need the following dependencies installed in your computer:

Compiling

With all the dependencies installed, in the project's root folder run the command:

$ task cli os=<operating-system> arch=<architecture>

Where:

  • <operating-system>: can be windows, darwin (macOS), or linux.
  • <architecture>: can be amd64 or arm64.

For example, if I wanted to build the CLI for Windows, on architecture AMD64, I would run the command:

$ task cli os=windows arch=amd64

📝 License

mediasim is released under the Apache 2.0 License. See LICENSE for details.

👨🏾‍💻 Author

Vinicius Egidio (vinicius.io)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddImageType

func AddImageType(types ...string)

AddImageType adds one or more image type extensions to the list of valid image types.

func AddVideoType

func AddVideoType(types ...string)

AddVideoType adds one or more video type extensions to the list of valid video types.

func CalculateSimilarity

func CalculateSimilarity(media1, media2 Media) float64

CalculateSimilarity computes a similarity score between two Media objects. Returns a value between 0 and 1, where higher values indicate greater similarity.

func GroupMedia

func GroupMedia(media []Media, threshold float64) [][]Media

GroupMedia organizes a list of media objects into groups based on a similarity threshold.

It uses a Disjoint Set Union (DSU) to cluster media items whose pairwise similarity score meets or exceeds the given threshold. Within each group (of at least two items), media are sorted by quality, prioritizing length, then resolution, then file size.

Parameters:

  • media: []Media Slice of Media objects to be grouped.
  • threshold: float64 Similarity threshold (0.0–1.0) for merging two media items.

Returns:

  • [][]Media A two-dimensional slice where each inner slice represents a group of media items (minimum length of 2), sorted by quality descending.

func LoadAndGroupMedia

func LoadAndGroupMedia(
	channel <-chan Result[Media],
	total int,
	threshold float64,
	ignoreErrors bool,
) <-chan LoadAndGroupResult

LoadAndGroupMedia performs media loading and similarity grouping in a single pass.

As each media item arrives from the input channel, it is immediately compared against all previously loaded items. Matches (similarity >= threshold) are unioned in a DSU. When the channel closes, groups are extracted.

Parameters:

  • channel: A channel of Result[Media] from LoadMediaFromFiles or LoadMediaFromDirectory.
  • total: The expected total number of items (used for DSU pre-allocation).
  • threshold: Similarity threshold (0.0–1.0) for merging two media items.
  • ignoreErrors: If true, loading errors are skipped; if false, the first error terminates processing.

Returns:

  • A channel of LoadAndGroupResult messages reporting progress and the final result.

func LoadMediaFromDirectory

func LoadMediaFromDirectory(directory string, options DirectoryOptions) (<-chan Result[Media], int)

LoadMediaFromDirectory loads Media objects from a specified directory based on the provided options.

Parameters:

  • directory: The path to the directory containing media files.
  • options: A DirectoryOptions struct specifying the configuration for loading media.

Returns:

  • A channel that will receive Result[Media] objects for each valid file processed.
  • An integer representing the total number of files that will be processed.

func LoadMediaFromFiles

func LoadMediaFromFiles(filePaths []string, options FilesOptions) <-chan Result[Media]

LoadMediaFromFiles loads Media objects from an array of file paths.

Parameters:

  • filePaths: An array of strings containing the paths to the image or video files.
  • options: The configuration options for loading multiple files.

Returns:

  • A channel that will receive Media objects for each valid file processed.
  • An error if there is an issue opening or decoding any of the files.

Types

type DirectoryOptions

type DirectoryOptions struct {
	IncludeImages bool
	IncludeVideos bool
	IsRecursive   bool
	Parallel      int
	FrameOptions
}

DirectoryOptions represents the configuration options for loading media from a directory.

Fields:

  • IncludeImages: A flag indicating whether to include image files.
  • IncludeVideos: A flag indicating whether to include video files.
  • IsRecursive: A flag indicating whether to search subdirectories recursively.
  • Parallel: The number of files to process in parallel.
  • FrameOptions: Frame transformation options (flip, rotate).

func (*DirectoryOptions) SetDefaults

func (o *DirectoryOptions) SetDefaults()

type FilesOptions

type FilesOptions struct {
	Parallel int
	FrameOptions
}

FilesOptions represents the configuration options for processing multiple files.

Fields:

  • Parallel: The number of files to process in parallel.
  • FrameOptions: Frame transformation options (flip, rotate).

func (*FilesOptions) SetDefaults

func (o *FilesOptions) SetDefaults()

type FrameOptions

type FrameOptions struct {
	FrameFlip   bool
	FrameRotate bool
}

FrameOptions represents the configuration options for loading media frames.

Fields:

  • FrameFlip: A flag indicating whether the frame should be flipped.
  • FrameRotate: A flag indicating whether the frame should be rotated.

type LoadAndGroupResult

type LoadAndGroupResult struct {
	// Media is the item just loaded (nil on error or final message).
	Media *Media
	// Loaded is the number of items successfully loaded so far.
	Loaded int
	// Err is non-nil if this item had a loading error.
	Err error
	// Done is true on the final message; Groups will be populated.
	Done bool
	// Groups contains the final grouped result, only populated when Done is true.
	Groups [][]Media
}

LoadAndGroupResult represents a progress update from the single-pass load-and-group operation.

type Media

type Media struct {

	// Name of the media.
	Name string `json:"name"`
	// Type of the media (e.g., image, video).
	Type string `json:"type"`
	// Width represents the width of the media in pixels.
	Width int `json:"width"`
	// Height represents the height of the media in pixels.
	Height int `json:"height"`
	// Size represents the size of the media file in bytes.
	Size int64 `json:"size"`
	// Length represents the duration of the media in seconds (for images this is always 0)
	Length int `json:"length"`
	// contains filtered or unexported fields
}

Media represents a media object.

func LoadMediaFromFile

func LoadMediaFromFile(filePath string, options FrameOptions) (*Media, error)

LoadMediaFromFile loads a Media object from the given file path.

Parameters:

  • filePath: The path to the image or video file.
  • options: The configuration options for loading frames.

Returns:

  • A pointer to a Media object containing the name and the converted image.
  • An error if there is an issue opening or decoding the file.

func LoadMediaFromImages

func LoadMediaFromImages(name string, images []image.Image, options FrameOptions) Media

LoadMediaFromImages creates a Media object from the given image or video.

Parameters:

  • name: The name of the media.
  • images: The images to be converted into a Media object.
  • options: The configuration options for loading frames.

Returns:

  • A Media object containing the name, type and frames of the media.

func (Media) Equal

func (m Media) Equal(other Media) bool

func (Media) String

func (m Media) String() string

Directories

Path Synopsis
internal
dsu
dtw

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL