Permalink
Browse files

Initial Commit

  • Loading branch information...
0 parents commit bdcc229d0f86191163021c44c50992cc4bed87ca @bahamas10 committed Jul 15, 2012
Showing with 309 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +150 −0 README.md
  3. +134 −0 bin/musicnamer.js
  4. +24 −0 package.json
@@ -0,0 +1 @@
+node_modules
150 README.md
@@ -0,0 +1,150 @@
+musicnamer
+==========
+
+Organize your music collection
+
+`musicnamer` is used to rename music files to clean filenames based
+on their music tags. By default, `musicnamer` can take your music files
+and rename them to a format like:
+
+ %artist%/%album%/%trackno% - %title%.%ext%
+
+This package is not meant to be used as a Node module, but rather
+as a command line tool
+
+Usage
+-----
+
+Invocation of `musicnamer` is simple: just run the program with files as arguments
+and it will do its thing on them.
+
+ ~$ musicnamer -h
+ Usage: musicnamer.js file1.mp3 file2.mp3 file3.mp3 ...
+
+ Given a list of files from the command line, rename them to
+ a clean filename (default '%artist%/%album%/%trackno% - %title%.%ext%')
+
+
+ Options (must be given as the first argument; all options are mutually exclusive)
+ --init | -i: Create a config file at /home/dave/.musicnamer.json
+ --dry-run | -n: Don't actually rename files, just print what actions would be taken
+ --tags | -t: Just print the tags from the files processesd, assumes --dry-run
+ --help | -h: Print this message and exit
+
+Examples
+--------
+
+To invoke `musicnamer`, simply pass a file over the command line as an argument
+
+ dave @ [ bahamas10 :: (SunOS) ] ~ $ musicnamer somesong.mp3
+ Error reading /home/dave/.musicnamer.json, Invoke with --init to create this file
+
+ ----- processing somesong.mp3 -----
+
+ Moving: somesong.mp3
+ -> To: BEING/Arrival/12 - The Singularity (Cosmists II).mp3
+
+Music namer renamed the file for us. What effectively happened here is this
+
+ mv somesong.mp3 "BEING/Arrival/12 - The Singularity (Cosmists II).mp3"
+
+**NOTE**: `musicnamer` by default renames files relative to your current directory.
+
+We can see the error message above complaining because the config file was not found/
+unreadable. We can fix this warning with this:
+
+ dave @ [ bahamas10 :: (SunOS) ] ~ $ musicnamer --init
+ Writing config to /home/dave/.musicnamer.json
+
+More details on the configuration file can be found in the `Configuration` section below.
+
+Now let's say we wanted to rename a bunch of files, but were worried about modifying
+them without testing. You can run `musicnamer` with a dry run option to show what action
+*would* have been taken.
+
+ dave @ [ bahamas10 :: (SunOS) ] ~ $ musicnamer somesong.mp3
+ ----- processing somesong.mp3 -----
+
+ Moving: somesong.mp3
+ -> To: BEING/Arrival/12 - The Singularity (Cosmists II).mp3
+ No action taken
+
+As you can see, the warning message now longer shows because we have created a config file.
+Also, `musicnamer` just printed out what it would have done, but didn't actually call rename(2)
+on any of the files.
+
+You can also test out files to get a glimpse into how `musicnamer` sees your files. There is a
+command line switch to have `musicnamer` print out the tags of files without renaming them.
+
+ dave @ [ bahamas10 :: (SunOS) ] ~ $ musicnamer --tags music/*.mp3
+ ----- processing song1.mp3 -----
+
+ { title: 'Stimulus',
+ artist: [ 'The Omega Experiment' ],
+ albumartist: [],
+ album: 'The Omega Experiment',
+ year: '2012',
+ track: { no: 2, of: 0 },
+ genre: [],
+ disk: { no: 0, of: 0 },
+ picture:
+ [ { format: '浩条⽥灪来cover\u0000',
+ data: <Buffer 00 ff db 00 43 00 02 01 01 01 01 01 02 01 01 01 02 02 02 02 02 04 03 02 02 02 02 05 04 04 03 04 06 05 06 06 06 05 06 06 06 07 09 08 06 07 09 07 06 06 08 ...> } ] }
+
+ ----- processing song2.mp3 -----
+
+ { title: 'Motion',
+ artist: [ 'The Omega Experiment' ],
+ albumartist: [],
+ album: 'The Omega Experiment',
+ year: '2012',
+ track: { no: 3, of: 0 },
+ genre: [],
+ disk: { no: 0, of: 0 },
+ picture:
+ [ { format: '浩条⽥灪来cover\u0000',
+ data: <Buffer 00 ff db 00 43 00 02 01 01 01 01 01 02 01 01 01 02 02 02 02 02 04 03 02 02 02 02 05 04 04 03 04 06 05 06 06 06 05 06 06 06 07 09 08 06 07 09 07 06 06 08 ...> } ] }
+
+This output is good to look for debugging information, without making
+any modifications to the filesystem.
+
+
+Configuration
+-------------
+
+`musicnamer --init` will create a config file in `~/.musicnamer.json`. This config file
+has a key called `format`, which has the format to use when renaming files.
+
+ ~$ cat ~/.musicnamer.json
+ {
+ "format": "%artist%/%album%/%trackno% - %title%.%ext%"
+ }
+
+The --init option will write out the default format value to the config file, this is the
+format that will be used if the config file is not present.
+
+Possible options for variables are:
+
+ %artist% : artist name
+ %album% : album name
+ %trackno% : track number
+ %title% : track title
+ %ext% : file extension
+
+
+Installation
+------------
+
+ npm install -g musicnamer
+
+
+Credits
+-------
+
+* Tags gathered with https://github.com/leetreveil/node-musicmetadata
+* Modeled after on [tvnamer](https://github.com/dbr/tvnamer)
+
+License
+-------
+
+MIT License
@@ -0,0 +1,134 @@
+#!/usr/bin/env node
+/**
+ * Music Namer
+ *
+ * Easily rename music files by their tags
+ *
+ * Author: Dave Eddy <dave@daveeddy.com>
+ * License: MIT
+ *
+ * Tags gathered with https://github.com/leetreveil/node-musicmetadata
+ * Based on TVnamer https://github.com/dbr/tvnamer
+ */
+
+// Requires and such
+var fs = require('fs'),
+ path = require('path'),
+ util = require('util'),
+ musicmetadata = require('musicmetadata'),
+ mkdirp = require('mkdirp'),
+ args = process.argv.slice(2),
+ config_file = path.join(process.env["HOME"], '.musicnamer.json'),
+ tags_only = false,
+ dry_run = false,
+ default_config = {
+ 'format': '%artist%/%album%/%trackno% - %title%.%ext%'
+ };
+
+/**
+ * Usage
+ *
+ * return the usage message
+ */
+function usage() {
+ return util.format([
+ 'Usage: %s file1.mp3 file2.mp3 file3.mp3 ...',
+ '',
+ 'Given a list of files from the command line, rename them to',
+ 'a clean filename (default \'%s\')',
+ '',
+ '',
+ 'Options (must be given as the first argument; all options are mutually exclusive)',
+ ' --init | -i: Create a config file at %s',
+ ' --dry-run | -n: Don\'t actually rename files, just print what actions would be taken',
+ ' --tags | -t: Just print the tags from the files processesd, assumes --dry-run',
+ ' --help | -h: Print this message and exit',
+ '',
+ ].join('\n'), path.basename(process.argv[1]), default_config.format, config_file);
+}
+
+/**
+ * Check tags
+ *
+ * Check a given set of metadata to make sure all tags are present
+ */
+function check_tags(meta) {
+ return meta.album && meta.title && meta.artist.length != 0;
+}
+
+/**
+ * Given a set of metadata, return the new path
+ * for the file
+ */
+function make_new_path(meta) {
+ var s = config.format || default_config.format;
+ return s.replace('%artist%', meta.artist[0])
+ .replace('%album%', meta.album)
+ .replace('%trackno%', meta.track.no)
+ .replace('%title%', meta.title)
+ .replace('%ext%', meta.ext);
+}
+
+// Check arguments
+if (args.length === 0) {
+ console.error(usage());
+ process.exit(1);
+}
+switch (args[0]) {
+ case '-h': case '--help':
+ console.log(usage());
+ process.exit(0);
+ case '-i': case '--init':
+ console.log('Writing config to %s', config_file);
+ fs.writeFileSync(config_file, JSON.stringify(default_config, null, 2))
+ process.exit(0);
+ case '-n': case '--dry-run':
+ dry_run = true;
+ args = args.slice(1);
+ break;
+ case '-t': case '--tags':
+ tags_only = true;
+ args = args.slice(1);
+ break;
+}
+
+// Try to get the config file
+var config = {};
+try {
+ config = JSON.parse(fs.readFileSync(config_file));
+} catch (e) {
+ console.error('Error reading %s, Invoke with --init to create this file\n',
+ config_file);
+}
+
+// Loop over the file arguments
+args.forEach(function(file) {
+ var parser = new musicmetadata(fs.createReadStream(file));
+ parser.on('metadata', function(meta) {
+ console.log('\n----- processing %s -----\n', file);
+
+ // Only print the tags if --tags is supplied
+ if (tags_only) return console.log(meta);
+
+ // Check that all arguments are present
+ if (!check_tags(meta)) {
+ console.error('Error reading tags/not all tags present');
+ console.error(meta);
+ return;
+ }
+
+ // Create the new pathname
+ meta.ext = path.extname(file) || '.mp3';
+ meta.ext = meta.ext.split('.')[1];
+ var new_path = make_new_path(meta);
+
+ console.log('Moving: %s', file);
+ console.log('-> To: %s', new_path);
+ if (dry_run) return console.log('No action taken');
+
+ // Make the folders and file
+ mkdirp.sync(path.dirname(new_path));
+ fs.renameSync(file, new_path);
+
+ });
+});
@@ -0,0 +1,24 @@
+{
+ "name": "musicnamer",
+ "description": "Organize your music collection",
+ "author": "Dave Eddy <dave@daveeddy.com> (http://www.daveeddy.com)",
+ "version": "0.0.0",
+ "repository": {
+ "url": "https://github.com/bahamas10/node-musicnamer.git",
+ "type": "git"
+ },
+ "main": "./bin/musicnamer.js",
+ "dependencies": {
+ "musicmetadata": "~ 0.1.7",
+ "mkdirp": "~ 0.3.3"
+ },
+ "devDependencies": {},
+ "optionalDependencies": {},
+ "bin": {
+ "musicnamer": "./bin/musicnamer.js"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "keywords": [ "music", "organize", "mp3", "flac", "tvnamer" ]
+}

0 comments on commit bdcc229

Please sign in to comment.