Permalink
Browse files

initial import

  • Loading branch information...
0 parents commit 9ebaa30b14bacf5c643471aa6f755bcfbdfa338b @youpy committed Mar 29, 2009
Showing with 365 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +4 −0 ChangeLog
  3. +36 −0 README
  4. +105 −0 Rakefile
  5. +129 −0 lib/scissor.rb
  6. +32 −0 scissor.gemspec
  7. BIN spec/fixtures/sample.mp3
  8. +46 −0 spec/scissor_spec.rb
  9. +3 −0 spec/spec.opts
  10. +8 −0 spec/spec_helper.rb
@@ -0,0 +1,2 @@
+pkg
+coverage
@@ -0,0 +1,4 @@
+== 0.0.1 / 2009-03-29
+
+* initial release
+
36 README
@@ -0,0 +1,36 @@
+= Scissor
+
+== Description
+utility to chop mp3 files
+
+== Installation
+
+=== Archive Installation
+
+ rake install
+
+=== Gem Installation
+
+ gem install youpy-scissor
+
+== Features/Problems
+
+== Synopsis
+
+ foo = Scissor.new('foo.mp3')
+ var = Scissor.new('bar.mp3')
+
+ # concat
+ (foo + bar).to_file('foobar.mp3')
+
+ # slice + concat
+ (foo.slice(10, 1) + bar.slice(2,3)).to_file('slicefoobar.mp3')
+
+ # slice + concat + loop
+ ((foo.slice(10, 1) + bar.slice(2,3)) * 3).to_file('slicefoobarloop.mp3')
+
+== Copyright
+
+Author:: youpy <youpy@buycheapviagraonlinenow.com>
+Copyright:: Copyright (c) 2009 youpy
+License:: MIT
105 Rakefile
@@ -0,0 +1,105 @@
+require 'rubygems'
+require 'rake'
+require 'rake/clean'
+require 'spec/rake/spectask'
+require 'rake/packagetask'
+require 'rake/gempackagetask'
+require 'rake/rdoctask'
+require 'rake/contrib/rubyforgepublisher'
+require 'rake/contrib/sshpublisher'
+require 'fileutils'
+include FileUtils
+
+NAME = "scissor"
+AUTHOR = "youpy"
+EMAIL = "youpy@buycheapviagraonlinenow.com"
+DESCRIPTION = "utility to chop mp3 files"
+RUBYFORGE_PROJECT = "scissor"
+HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
+BIN_FILES = %w( )
+VERS = "0.0.1"
+
+REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
+CLEAN.include ['**/.*.sw?', '*.gem', '.config']
+RDOC_OPTS = [
+ '--title', "#{NAME} documentation",
+ "--charset", "utf-8",
+ "--opname", "index.html",
+ "--line-numbers",
+ "--main", "README",
+ "--inline-source",
+]
+
+task :default => [:spec]
+task :package => [:clean]
+
+Spec::Rake::SpecTask.new do |t|
+ t.spec_opts = ['--options', "spec/spec.opts"]
+ t.spec_files = FileList['spec/*_spec.rb']
+ t.rcov = true
+end
+
+spec = Gem::Specification.new do |s|
+ s.name = NAME
+ s.version = VERS
+ s.platform = Gem::Platform::RUBY
+ s.has_rdoc = true
+ s.extra_rdoc_files = ["README", "ChangeLog"]
+ s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
+ s.summary = DESCRIPTION
+ s.description = DESCRIPTION
+ s.author = AUTHOR
+ s.email = EMAIL
+ s.executables = BIN_FILES
+ s.rubyforge_project = RUBYFORGE_PROJECT
+ s.bindir = "bin"
+ s.require_path = "lib"
+ s.homepage = HOMEPATH
+ s.test_files = Dir["test/test_*.rb"]
+
+ s.add_dependency('ruby-mp3info')
+ #s.required_ruby_version = '>= 1.8.2'
+
+ s.files = %w(README ChangeLog Rakefile) +
+ Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
+ Dir.glob("ext/**/*.{h,c,rb}") +
+ Dir.glob("examples/**/*.rb") +
+ Dir.glob("tools/*.rb")
+
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
+end
+
+Rake::GemPackageTask.new(spec) do |p|
+ p.need_tar = true
+ p.gem_spec = spec
+end
+
+task :install do
+ name = "#{NAME}-#{VERS}.gem"
+ sh %{rake package}
+ sh %{sudo gem install pkg/#{name}}
+end
+
+task :uninstall => [:clean] do
+ sh %{sudo gem uninstall #{NAME}}
+end
+
+
+Rake::RDocTask.new do |rdoc|
+ rdoc.rdoc_dir = 'html'
+ rdoc.options += RDOC_OPTS
+ rdoc.template = "resh"
+ #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ if ENV['DOC_FILES']
+ rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
+ else
+ rdoc.rdoc_files.include('README', 'ChangeLog')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+ rdoc.rdoc_files.include('ext/**/*.c')
+ end
+end
+
+desc 'Show information about the gem.'
+task :debug_gem do
+ puts spec.to_ruby
+end
@@ -0,0 +1,129 @@
+require 'mp3info'
+require 'fileutils'
+
+include FileUtils
+
+class Scissor
+ class Error < StandardError; end
+ class CommandNotFound < Error; end
+
+ attr_reader :fragments
+
+ def initialize(filename = nil)
+ which('ffmpeg')
+ which('mp3wrap')
+
+ @fragments = []
+
+ if filename
+ @fragments << Fragment.new(
+ filename,
+ 0,
+ Mp3Info.new(filename).length)
+ end
+ end
+
+ def add_fragment(fragment)
+ @fragments << fragment
+ end
+
+ def duration
+ @fragments.inject(0) do |memo, fragment|
+ memo += fragment.duration
+ end
+ end
+
+ def slice(start, length)
+ new_mp3 = self.class.new()
+ remain = length
+
+ @fragments.each do |fragment|
+ if start >= fragment.duration
+ start -= fragment.duration
+
+ next
+ end
+
+ if (start + fragment.duration) >= remain
+ new_mp3.add_fragment(Fragment.new(
+ fragment.filename,
+ fragment.start + start,
+ remain))
+
+ break
+ else
+ remain = remain - fragment.duration
+ new_mp3.add_fragment(Fragment.new(
+ fragment.filename,
+ fragment.start + start,
+ fragment.duration))
+
+ start = 0
+ end
+ end
+
+ new_mp3
+ end
+
+ def which(command)
+ result = `which #{command}`
+ $?.exitstatus == 0 ? result.chomp :
+ (raise CommandNotFound.new(command + ' not found'))
+ end
+
+ def +(other)
+ other.fragments.each do |fragment|
+ add_fragment(fragment)
+ end
+
+ self
+ end
+
+ def *(count)
+ orig_fragments = @fragments.clone
+
+ (count - 1).times do
+ orig_fragments.each do |fragment|
+ add_fragment(fragment)
+ end
+ end
+
+ self
+ end
+
+ def to_file(filename)
+ outfiles = []
+ tmpdir = '/tmp/scissor-' + $$.to_s
+ mkdir tmpdir
+
+ # slice mp3 files
+ @fragments.each_with_index do |fragment, index|
+ outfile = tmpdir + '/' + index.to_s + '.mp3'
+ outfiles << outfile
+ cmd = "ffmpeg -i #{fragment.filename} -ss #{fragment.start} -t #{fragment.duration} #{outfile}"
+ system cmd
+ end
+
+ # concat mp3 files
+ cmd = "mp3wrap #{filename} #{outfiles.join(' ')}"
+ system cmd
+
+ # fix duration and rename
+ cmd = "ffmpeg -i #{filename.sub(/\.mp3$/, '_MP3WRAP.mp3')} -acodec copy #{filename}"
+ system cmd
+
+ rm_rf tmpdir
+
+ open(filename)
+ end
+
+ class Fragment
+ attr_reader :filename, :start, :duration
+
+ def initialize(filename, start, duration)
+ @filename = filename
+ @start = start
+ @duration = duration
+ end
+ end
+end
@@ -0,0 +1,32 @@
+Gem::Specification.new do |s|
+ s.name = %q{scissor}
+ s.version = "0.0.1"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["youpy"]
+ s.date = %q{2009-03-29}
+ s.description = %q{utility to chop mp3 files}
+ s.email = %q{youpy@buycheapviagraonlinenow.com}
+ s.extra_rdoc_files = ["README", "ChangeLog"]
+ s.files = ["README", "ChangeLog", "Rakefile", "lib/scissor.rb"]
+ s.has_rdoc = true
+ s.homepage = %q{http://scissor.rubyforge.org}
+ s.rdoc_options = ["--title", "scissor documentation", "--charset", "utf-8", "--opname", "index.html", "--line-numbers", "--main", "README", "--inline-source", "--exclude", "^(examples|extras)/"]
+ s.require_paths = ["lib"]
+ s.rubyforge_project = %q{scissor}
+ s.rubygems_version = %q{1.2.0}
+ s.summary = %q{utility to chop mp3 files}
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 2
+
+ if current_version >= 3 then
+ s.add_runtime_dependency(%q<ruby-mp3info>, [">= 0"])
+ else
+ s.add_dependency(%q<ruby-mp3info>, [">= 0"])
+ end
+ else
+ s.add_dependency(%q<ruby-mp3info>, [">= 0"])
+ end
+end
Binary file not shown.
@@ -0,0 +1,46 @@
+$:.unshift File.dirname(__FILE__)
+
+require 'spec_helper'
+require 'fileutils'
+
+include FileUtils
+
+describe Scissor do
+ before do
+ @mp3 = Scissor.new(fixture('sample.mp3'))
+ mkdir '/tmp/scissor-test'
+ end
+
+ after do
+ rm_rf '/tmp/scissor-test'
+ end
+
+ it "should get duration" do
+ @mp3.should respond_to(:duration)
+ @mp3.duration.should eql(178.183)
+ end
+
+ it "should slice" do
+ @mp3.should respond_to(:slice)
+ @mp3.slice(0, 120).duration.should eql(120)
+ @mp3.slice(150, 20).duration.should eql(20)
+ end
+
+ it "should paste" do
+ new_mp3 = @mp3.slice(0, 120) + @mp3.slice(150, 20)
+ new_mp3.duration.should eql(140)
+ end
+
+ it "should loop" do
+ new_mp3 = @mp3.slice(0, 10) * 3
+ new_mp3.duration.should eql(30)
+ end
+
+ it "should write to file" do
+ new_mp3 = @mp3.slice(0, 120) + @mp3.slice(150, 20)
+ file = new_mp3.to_file('/tmp/scissor-test/out.mp3')
+ file.should be_an_instance_of(File)
+ File.exist?(file).should be_true
+ Scissor.new(file.path).duration.to_i.should eql(140)
+ end
+end
@@ -0,0 +1,3 @@
+-c
+-fs
+
@@ -0,0 +1,8 @@
+$:.unshift File.dirname(__FILE__) + '/../lib/'
+
+require 'scissor'
+
+def fixture(filename)
+ File.dirname(__FILE__) + '/fixtures/' + filename
+end
+

0 comments on commit 9ebaa30

Please sign in to comment.