├── .rspec ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── fancy_audio ├── fancy_audio.gemspec ├── lib ├── fancy_audio.rb └── fancy_audio │ ├── pretty_printer.rb │ └── version.rb └── spec ├── fancy_audio_spec.rb ├── resources ├── song1.jpg ├── song1.mp3 └── song2.mp3 └── spec_helper.rb /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'ruby-mp3info' 4 | gem 'pry' 5 | 6 | gemspec 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | fancy_audio (0.0.4) 5 | ruby-mp3info (~> 0.8.5) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | coderay (1.1.0) 11 | diff-lcs (1.2.5) 12 | method_source (0.8.2) 13 | pry (0.10.1) 14 | coderay (~> 1.1.0) 15 | method_source (~> 0.8.1) 16 | slop (~> 3.4) 17 | rake (10.4.2) 18 | rspec (3.1.0) 19 | rspec-core (~> 3.1.0) 20 | rspec-expectations (~> 3.1.0) 21 | rspec-mocks (~> 3.1.0) 22 | rspec-core (3.1.7) 23 | rspec-support (~> 3.1.0) 24 | rspec-expectations (3.1.2) 25 | diff-lcs (>= 1.2.0, < 2.0) 26 | rspec-support (~> 3.1.0) 27 | rspec-mocks (3.1.3) 28 | rspec-support (~> 3.1.0) 29 | rspec-support (3.1.2) 30 | ruby-mp3info (0.8.7) 31 | slop (3.6.0) 32 | 33 | PLATFORMS 34 | ruby 35 | 36 | DEPENDENCIES 37 | bundler (~> 1.5) 38 | fancy_audio! 39 | pry 40 | rake 41 | rspec 42 | ruby-mp3info 43 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Ajit Singh 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fancy_audio 2 | [![Gem Version](https://badge.fury.io/rb/fancy_audio.svg)](http://badge.fury.io/rb/fancy_audio) 3 | [![HitCount](http://hits.dwyl.io/ajitsing/fancy_audio.svg)](http://hits.dwyl.io/ajitsing/fancy_audio) 4 | ![Gem Downloads](http://ruby-gem-downloads-badge.herokuapp.com/fancy_audio?type=total) 5 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=102)](https://opensource.org/licenses/MIT) 6 | [![Twitter Follow](https://img.shields.io/twitter/follow/Ajit5ingh.svg?style=social)](https://twitter.com/Ajit5ingh) 7 | 8 | 9 | A gem to add album cover to audio file 10 | 11 | ## Documentation 12 | http://www.singhajit.com/add-album-cover-to-mp3-file/ 13 | 14 | ## Demo Video 15 | [![IMAGE ALT TEXT](http://img.youtube.com/vi/woqHqBDslWo/0.jpg)](https://www.youtube.com/watch?v=woqHqBDslWo "Demo") 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( http://github.com/ajitsing/fancy_audio ) 20 | 2. Create your feature branch 21 | 3. add feature 22 | 4. add tests 23 | 4. Run tests using 'rake' or 'rake spec' 24 | 4. Push to the branch 25 | 5. Create new Pull Request 26 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | task :spec do 4 | sh 'rspec' 5 | end 6 | 7 | task :default => :spec 8 | -------------------------------------------------------------------------------- /bin/fancy_audio: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'fancy_audio' 4 | include FancyAudio::Operations 5 | include FancyAudio::PrettyPrinter 6 | 7 | def print_help 8 | help = <<-info 9 | fancy_audio --all /path/to/songs image_file #=> attach image_file to all audio_files.(default songs path is current directory) 10 | fancy_audio audio_file image_file #=> attach image_file to audio_file 11 | fancy_audio #=> attach all audio and images with same name(default current dir) e.g song1.mp3 and song1.jpg 12 | fancy_audio path/to/files #=> attach all audio and images with same name(cutom path to dir) e.g song1.mp3 and song1.jpg 13 | fancy_audio --h #=> to print help 14 | 15 | To see a demo visit - http://www.singhajit.com/fancyaudio-gem-to-add-album-cover-to-audio-file/ 16 | info 17 | 18 | print_info help 19 | end 20 | 21 | def add_image_to_all_songs 22 | second = ARGV[1] 23 | third = ARGV[2] 24 | 25 | if ARGV.size == 2 26 | add_image_to_all second 27 | elsif ARGV.size == 3 28 | add_image_to_all second, third 29 | end 30 | end 31 | 32 | def execute 33 | first = ARGV[0] 34 | second = ARGV[1] 35 | 36 | if first == '--h' && ARGV.size == 1 37 | print_help 38 | 39 | elsif first == '--all' 40 | add_image_to_all_songs 41 | 42 | elsif !first.nil? && !second.nil? && ARGV.size == 2 43 | add_image first, second 44 | 45 | elsif ARGV.size.zero? 46 | add_image_smartly 47 | 48 | elsif ARGV.size == 1 49 | add_image_smartly first 50 | 51 | else 52 | print_error "Wrong Usages! To know the right usages type 'fancy_audio --h'" 53 | end 54 | end 55 | 56 | begin 57 | execute 58 | rescue 59 | error_msg = <<-error 60 | Something went wrong! Or usages is incorrect 61 | To understand the correct usages visit - http://www.singhajit.com/fancyaudio-gem-to-add-album-cover-to-audio-file/ 62 | error 63 | 64 | print_error error_msg 65 | end 66 | 67 | -------------------------------------------------------------------------------- /fancy_audio.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'fancy_audio/version' 5 | 6 | Gem::Specification.new do |s| 7 | s.name = 'fancy_audio' 8 | s.version = FancyAudio::VERSION 9 | s.date = '2015-07-25' 10 | s.summary = 'Gem to add an album cover to the audio' 11 | s.description = s.summary 12 | s.authors = ['Ajit Singh'] 13 | s.email = 'jeetsingh.ajit@gamil.com' 14 | s.license = 'MIT' 15 | s.homepage = 'http://www.singhajit.com/fancyaudio-gem-to-add-album-cover-to-audio-file/' 16 | 17 | s.files = `git ls-files -z`.split("\x0") 18 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | s.test_files = s.files.grep(%r{^(test|spec|features)/}) 20 | s.require_paths = ["lib"] 21 | 22 | s.add_dependency 'ruby-mp3info', '~> 0.8.5' 23 | s.add_development_dependency "bundler", "~> 1.5" 24 | s.add_development_dependency "rake" 25 | s.add_development_dependency "rspec" 26 | end 27 | -------------------------------------------------------------------------------- /lib/fancy_audio.rb: -------------------------------------------------------------------------------- 1 | require 'mp3info' 2 | require_relative 'fancy_audio/pretty_printer' 3 | 4 | module FancyAudio 5 | module Operations 6 | include FancyAudio::PrettyPrinter 7 | 8 | IMAGE_NOT_FOUND = 'File Not Found' 9 | 10 | def add_image(audio_file, image) 11 | return unless files_present(audio_file, image) 12 | 13 | image_file = File.new(image, 'rb') 14 | Mp3Info.open(audio_file) do |audio| 15 | audio.tag2.remove_pictures 16 | audio.tag2.add_picture(image_file.read) 17 | end 18 | end 19 | 20 | def add_image_to_all(dir = `pwd`.chop, image) 21 | audio_files = Dir[dir + "/*.mp3"] 22 | 23 | audio_files.each do |audio_file| 24 | add_image(audio_file, image) 25 | end 26 | print_info "done!" 27 | end 28 | 29 | def add_image_smartly(dir = `pwd`.chop) 30 | unavialble_images = [] 31 | changed_audio_files = {} 32 | audio_files = Dir[dir + "/*.mp3"] 33 | 34 | audio_files.each do |audio_file| 35 | file_name_without_ext = dir + "/#{File.basename(audio_file, '.mp3')}" 36 | image_file = get_image_file(file_name_without_ext) 37 | 38 | if(image_file == IMAGE_NOT_FOUND) 39 | unavialble_images << audio_file 40 | else 41 | add_image(audio_file, image_file) 42 | changed_audio_files[audio_file] = image_file 43 | end 44 | end 45 | 46 | print_modified_files changed_audio_files 47 | print "\n\n" 48 | print_unmodified_files unavialble_images 49 | print_info "No audio files found!!" if audio_files.empty? 50 | end 51 | 52 | private 53 | def files_present(audio_file, image_file) 54 | audio_file_exists = File.exist?(audio_file) 55 | image_file_exists = File.exist?(image_file) 56 | 57 | if !audio_file_exists 58 | print_error "#{audio_file} does not exists!\n" 59 | elsif !image_file_exists 60 | print_error "#{image_file} does not exists!\n" 61 | end 62 | 63 | audio_file_exists && image_file_exists 64 | end 65 | 66 | def print_modified_files(files) 67 | return if files.empty? 68 | print_info("Modified Audio Files\n") 69 | files.each {|audio, image| print_success(audio + " + #{image}\n")} 70 | end 71 | 72 | def print_unmodified_files(files) 73 | return if files.empty? 74 | print_info("Unmodified Audio Files - May be image is not present for these audios\n") 75 | print_info("Convertor only supports .jpeg, .jpg and .png image files\n") 76 | files.each {|image| print_error(image+"\n")} 77 | end 78 | 79 | def get_image_file(file) 80 | return (file + ".jpeg") if File.exist?(file + ".jpeg") 81 | return (file + ".jpg") if File.exist?(file + ".jpg") 82 | return (file + ".png") if File.exist?(file + ".png") 83 | 84 | IMAGE_NOT_FOUND 85 | end 86 | end 87 | end 88 | 89 | -------------------------------------------------------------------------------- /lib/fancy_audio/pretty_printer.rb: -------------------------------------------------------------------------------- 1 | module FancyAudio 2 | module PrettyPrinter 3 | def colorize(text, color_code) 4 | "#{color_code}#{text}\e[0m" 5 | end 6 | 7 | def red(text); colorize(text, "\e[31m"); end 8 | def green(text); colorize(text, "\e[32m"); end 9 | def yellow(text); colorize(text, "\e[1m\e[33m"); end 10 | 11 | def print_info(msg) 12 | STDOUT.write yellow(msg) 13 | end 14 | 15 | def print_error(msg) 16 | STDOUT.write red(msg) 17 | end 18 | 19 | def print_success(msg) 20 | STDOUT.write green(msg) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/fancy_audio/version.rb: -------------------------------------------------------------------------------- 1 | module FancyAudio 2 | VERSION = "0.0.4" 3 | end 4 | -------------------------------------------------------------------------------- /spec/fancy_audio_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe :FancyAudio do 4 | 5 | before(:each) do 6 | remove_pictures_from_songs 7 | end 8 | 9 | it 'should add image to the song' do 10 | current_dir = File.expand_path File.dirname __FILE__ 11 | image_file = current_dir + '/resources/song1.jpg' 12 | audio_file = current_dir + '/resources/song1.mp3' 13 | 14 | add_image audio_file, image_file 15 | assert_audio_has_image audio_file 16 | end 17 | 18 | it 'should handle gracefully when file is not present' do 19 | current_dir = File.expand_path File.dirname __FILE__ 20 | unavailable_audio_file = current_dir + '/resources/unavailable_song.mp3' 21 | unavailable_image_file = current_dir + '/resources/unavailable_image.jpg' 22 | 23 | image_file = current_dir + '/resources/song1.jpg' 24 | audio_file = current_dir + '/resources/song1.mp3' 25 | 26 | add_image unavailable_audio_file, image_file 27 | add_image audio_file, unavailable_image_file 28 | 29 | assert_audio_does_not_have_image audio_file 30 | end 31 | 32 | it 'should add image to the song smartly' do 33 | dir = File.expand_path File.dirname(__dir__) + '/spec/resources' 34 | audio_file = dir + '/song1.mp3' 35 | 36 | add_image_smartly dir 37 | assert_audio_has_image audio_file 38 | end 39 | 40 | it 'should add image to the song in the current directory' do 41 | dir = File.expand_path File.dirname(__dir__) + '/spec/resources' 42 | audio_file = dir + '/song1.mp3' 43 | Dir.chdir dir do 44 | add_image_smartly 45 | assert_audio_has_image audio_file 46 | end 47 | end 48 | 49 | it 'should add image to all songs' do 50 | current_dir = File.expand_path File.dirname __FILE__ 51 | audio_file_1 = current_dir + '/resources/song1.mp3' 52 | audio_file_2 = current_dir + '/resources/song2.mp3' 53 | image_file = current_dir + '/resources/song1.jpg' 54 | 55 | add_image_to_all(current_dir + '/resources/', image_file) 56 | assert_audio_has_image audio_file_1 57 | assert_audio_has_image audio_file_2 58 | end 59 | end 60 | 61 | -------------------------------------------------------------------------------- /spec/resources/song1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajitsing/fancy_audio/31a25879a0cea8a9fb1fe0be052ba8cfbf12d33f/spec/resources/song1.jpg -------------------------------------------------------------------------------- /spec/resources/song1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajitsing/fancy_audio/31a25879a0cea8a9fb1fe0be052ba8cfbf12d33f/spec/resources/song1.mp3 -------------------------------------------------------------------------------- /spec/resources/song2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajitsing/fancy_audio/31a25879a0cea8a9fb1fe0be052ba8cfbf12d33f/spec/resources/song2.mp3 -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause this 4 | # file to always be loaded, without a need to explicitly require it in any files. 5 | # 6 | # Given that it is always loaded, you are encouraged to keep this file as 7 | # light-weight as possible. Requiring heavyweight dependencies from this file 8 | # will add to the boot time of your test suite on EVERY test run, even for an 9 | # individual file that may not need all of that loaded. Instead, consider making 10 | # a separate helper file that requires the additional dependencies and performs 11 | # the additional setup, and require it from the spec files that actually need it. 12 | # 13 | # The `.rspec` file also contains a few flags that are not defaults but that 14 | # users commonly want. 15 | # 16 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 17 | require 'mp3info' 18 | require './lib/fancy_audio.rb' 19 | 20 | include FancyAudio::Operations 21 | 22 | def assert_audio_has_image(audio) 23 | Mp3Info.open(audio) do |song| 24 | song.tag2.pictures.empty?.should be_falsy 25 | end 26 | end 27 | 28 | def assert_audio_does_not_have_image(audio) 29 | Mp3Info.open(audio) do |song| 30 | song.tag2.pictures.empty?.should be_truthy 31 | end 32 | end 33 | 34 | def remove_pictures_from_songs 35 | current_dir = File.expand_path File.dirname __FILE__ 36 | songs = Dir[current_dir + "/resources/*.mp3"] 37 | 38 | songs.each do |song| 39 | Mp3Info.open(song) do |song_file| 40 | song_file.tag2.remove_pictures 41 | end 42 | end 43 | end 44 | 45 | RSpec.configure do |config| 46 | # rspec-expectations config goes here. You can use an alternate 47 | # assertion/expectation library such as wrong or the stdlib/minitest 48 | # assertions if you prefer. 49 | config.expect_with :rspec do |c| 50 | c.syntax = :should 51 | end 52 | 53 | config.mock_with :rspec do |c| 54 | c.syntax = :should 55 | end 56 | # The settings below are suggested to provide a good initial experience 57 | # with RSpec, but feel free to customize to your heart's content. 58 | =begin 59 | # These two settings work together to allow you to limit a spec run 60 | # to individual examples or groups you care about by tagging them with 61 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 62 | # get run. 63 | config.filter_run :focus 64 | config.run_all_when_everything_filtered = true 65 | 66 | # Limits the available syntax to the non-monkey patched syntax that is recommended. 67 | # For more details, see: 68 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 69 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 70 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 71 | config.disable_monkey_patching! 72 | 73 | # This setting enables warnings. It's recommended, but in some cases may 74 | # be too noisy due to issues in dependencies. 75 | config.warnings = true 76 | 77 | # Many RSpec users commonly either run the entire suite or an individual 78 | # file, and it's useful to allow more verbose output when running an 79 | # individual spec file. 80 | if config.files_to_run.one? 81 | # Use the documentation formatter for detailed output, 82 | # unless a formatter has already been configured 83 | # (e.g. via a command-line flag). 84 | config.default_formatter = 'doc' 85 | end 86 | 87 | # Print the 10 slowest examples and example groups at the 88 | # end of the spec run, to help surface which specs are running 89 | # particularly slow. 90 | config.profile_examples = 10 91 | 92 | # Run specs in random order to surface order dependencies. If you find an 93 | # order dependency and want to debug it, you can fix the order by providing 94 | # the seed, which is printed after each run. 95 | # --seed 1234 96 | config.order = :random 97 | 98 | # Seed global randomization in this process using the `--seed` CLI option. 99 | # Setting this allows you to use `--seed` to deterministically reproduce 100 | # test failures related to randomization by passing the same `--seed` value 101 | # as the one that triggered the failure. 102 | Kernel.srand config.seed 103 | =end 104 | end 105 | --------------------------------------------------------------------------------