plexify 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -5,5 +5,7 @@ gemspec
5
5
 
6
6
  gem "ruby-tmdb", ">= 0.2.1"
7
7
  gem "colorize", ">= 0.5.8"
8
- gem "text", ">= 1.2.1"
9
8
  gem "ruby-progressbar", ">= 1.0.2"
9
+ gem "debugger", ">= 1.2.2"
10
+ gem "rspec", ">= 2.12.0"
11
+ gem "amatch", ">= 0.2.10"
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Plexify
2
2
 
3
- Currently in development. Not working yet.
3
+ Plexify is a file organizer tool to manage medias. It analyses files and search for movies in TheMovieDB to have
4
+ informations about them and create good folder names and add some additional stuffs like posters, desriptions
5
+ (these two lasts aren't supported yet, but will be ;))
4
6
 
5
- TODO: Write a gem description
6
7
 
7
8
  ## Installation
8
9
 
@@ -18,14 +19,36 @@ Or install it yourself as:
18
19
 
19
20
  $ gem install plexify
20
21
 
22
+ ## Ruby
23
+
24
+ Plexify is compatible with
25
+
26
+ ruby 1.9.3
27
+
21
28
  ## Usage
22
29
 
23
- TODO: Write usage instructions here
30
+ Plexify analyses files and move them to an oranized folder, so it creates destination folders and media folders.
31
+
32
+ The default usage is:
33
+
34
+ $ plexify -s /media/Temp -d /media/PlexMediaFolder
35
+
36
+ or more simple
37
+
38
+ $ plexify /media/Temp /media/PlexMediaFolder
39
+
40
+ If you specify a destination with the -d flag, it will create two folders inside the destination folder named "Movies" and "TV_Shows".
41
+
42
+ You can also specify movies and series folders like that:
43
+
44
+ $ plexify -s /media/Temp --movies-destination /media/PlexMediaFolder/Movies --series-destination /media/PlexMediaFolder/Series
45
+
46
+ If you aren't really sure about the tool, you can either use plexify in test mode like that:
47
+
48
+ $ plexify -s /media/Temp -d /media/PlexMediaFolder --test
49
+
50
+ It will just print found medias and not move files.
24
51
 
25
- ## Contributing
52
+ ## Contributors
26
53
 
27
- 1. Fork it
28
- 2. Create your feature branch (`git checkout -b my-new-feature`)
29
- 3. Commit your changes (`git commit -am 'Add some feature'`)
30
- 4. Push to the branch (`git push origin my-new-feature`)
31
- 5. Create new Pull Request
54
+ 1. Pierre FILSTROFF ([reaper](https://github.com/reaper/))
data/Rakefile CHANGED
@@ -1 +1,3 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new('spec')
data/lib/plexify.rb CHANGED
@@ -5,19 +5,23 @@ require 'optparse'
5
5
  require 'colorize'
6
6
  require 'ruby-tmdb'
7
7
  require 'yaml'
8
- require 'text'
8
+ require 'amatch'
9
9
 
10
10
  Dir[File.dirname(__FILE__) + "/plexify/**/*"].each{ |file| require file }
11
11
 
12
12
  module Plexify
13
- class Plexify
14
- def initialize(args)
15
- @opts = Execute::Plexify.new(args)
16
- end
13
+ class Plexify
14
+ def initialize(args)
15
+ @opts = Execute::Plexify.new(args)
16
+ end
17
17
 
18
- # Run plexify !
19
- def run!
20
- @opts.parse!
21
- end
18
+ # Run plexify !
19
+ def run!
20
+ @opts.parse!
22
21
  end
22
+ end
23
+
24
+ def self.version
25
+ return "Plexify version #{VERSION}"
26
+ end
23
27
  end
@@ -1,170 +1,180 @@
1
1
  module Plexify
2
- module Execute
3
- class Plexify
4
- # Plexify::Execute initialize method
5
- def initialize(args)
6
- @args = args
7
- @options = {}
8
- @missing_args = []
2
+ module Execute
3
+ class Plexify
4
+ # Plexify::Execute initialize method
5
+ def initialize(args)
6
+ @args = args
7
+ @options = {}
8
+ @missing_args = []
9
+ end
10
+
11
+ # Parses the command-line arguments and execute files processing
12
+ def parse!
13
+ begin
14
+ @opts = OptionParser.new(&method(:set_opts))
15
+ @opts.parse!(@args)
16
+ check_arguments
17
+
18
+ if @args.any?
19
+ @options[:source] = @args[0] unless @options[:source]
20
+ @options[:destination] = @args[1] if @args[1] && !@options[:destination]
21
+ end
22
+
23
+ process_result
24
+
25
+ # Puts missing arguments
26
+ rescue OptionParser::MissingArgument => e
27
+ built_string = e.message
28
+ for arg in @missing_args
29
+ built_string += arg
30
+ unless @missing_args.last == arg
31
+ built_string += ", "
32
+ else
33
+ built_string += "\n\n"
9
34
  end
35
+ end
36
+ puts built_string
37
+ puts @opts
10
38
 
11
- # Parses the command-line arguments and execute files processing
12
- def parse!
13
- begin
14
- @opts = OptionParser.new(&method(:set_opts))
15
- @opts.parse!(@args)
16
- check_arguments
17
-
18
- if @args.any?
19
- @options[:source] = @args[0] unless @options[:source]
20
- @options[:destination] = @args[1] unless @options[:destination]
21
- end
22
-
23
- process_result
24
-
25
- # Puts missing arguments
26
- rescue OptionParser::MissingArgument => e
27
- built_string = e.message
28
- for arg in @missing_args
29
- built_string += arg
30
- unless @missing_args.last == arg
31
- built_string += ", "
32
- else
33
- built_string += "\n\n"
34
- end
35
- end
36
- puts built_string
37
- puts @opts
38
-
39
- # Puts exception message
40
- rescue Exception => e
41
- raise e if @options[:trace] || e.is_a?(SystemExit)
42
-
43
- print "\n#{e.class}: " unless e.class == RuntimeError
44
- puts "#{e.message}"
45
- puts " Use --trace for backtrace."
46
- end
47
- exit 0
48
- end
39
+ # Puts exception message
40
+ rescue Exception => e
41
+ raise e if @options[:trace] || e.is_a?(SystemExit)
49
42
 
50
- private
51
- # Check missing arguments
52
- def check_arguments
53
- return if @args.size == 2
43
+ print "\n#{e.class}: " unless e.class == RuntimeError
44
+ puts "#{e.message}"
45
+ puts " Use --trace for backtrace."
46
+ end
47
+ exit 0
48
+ end
54
49
 
55
- @missing_args << "-s [source]" if !@options[:source] && !@args[0]
56
- @missing_args << "-d [destination]" if !@options[:destination] && !@options[:movies_destination] && !@options[:series_destination]
57
- @missing_args << "--movies-destination [destination]" if !@options[:destination] && !@options[:movies_destination] && !@options[:series_destination]
58
- @missing_args << "--series-destination [destination]" if !@options[:destination] && !@options[:series_destination] && !@options[:movies_destination]
50
+ private
51
+ # Check missing arguments
52
+ def check_arguments
53
+ return if @args.size == 2
59
54
 
60
- if @missing_args.any?
61
- raise OptionParser::MissingArgument
62
- end
63
- end
55
+ @missing_args << "-s [source]" if !@options[:source] && !@args[0]
56
+ @missing_args << "-d [destination]" if !@options[:test] && !@options[:destination] && !@options[:movies_destination] && !@options[:series_destination]
57
+ @missing_args << "--movies-destination [destination]" if !@options[:test] && !@options[:destination] && !@options[:movies_destination] && !@options[:series_destination]
58
+ @missing_args << "--series-destination [destination]" if !@options[:test] && !@options[:destination] && !@options[:series_destination] && !@options[:movies_destination]
64
59
 
65
- # Set options definition for command-line execution
66
- def set_opts(opts)
67
- opts.banner = "Usage: plexify -s /media/temp --movies-destination /media/Movies --series-destination /media/Series\n\n"
60
+ if @missing_args.any?
61
+ raise OptionParser::MissingArgument
62
+ end
63
+ end
68
64
 
69
- opts.on('-s [source]', '--source [source]', 'Source folder which includes media files. Temp folder.') do |source|
70
- @options[:source] = source
71
- end
65
+ # Set options definition for command-line execution
66
+ def set_opts(opts)
67
+ opts.banner = "Usage: plexify -s /media/temp --movies-destination /media/Movies --series-destination /media/Series\n\n"
72
68
 
73
- opts.on('-d [destination]', '--destination [dest]', 'Destination folder to put organized.') do |destination|
74
- @options[:destination] = destination
75
- end
69
+ opts.on('-s [source]', '--source [source]', 'Source folder which includes media files. Temp folder.') do |source|
70
+ @options[:source] = source
71
+ end
76
72
 
77
- opts.on('--movies-destination [dest]', 'Destination folder to put organized movies files.') do |movies_destination|
78
- @options[:movies_destination] = movies_destination
79
- end
73
+ opts.on('-d [destination]', '--destination [dest]', 'Destination folder to put organized.') do |destination|
74
+ @options[:destination] = destination
75
+ end
80
76
 
81
- opts.on('--series-destination [dest]', 'Destination folder to put organized series files.') do |series_destination|
82
- @options[:series_destination] = series_destination
83
- end
77
+ opts.on('--movies-destination [dest]', 'Destination folder to put organized movies files.') do |movies_destination|
78
+ @options[:movies_destination] = movies_destination
79
+ end
84
80
 
85
- opts.on_tail('-t', '--test', 'Test files name searching in media databases: only print results.') do
86
- @options[:test] = true
87
- end
81
+ opts.on('--series-destination [dest]', 'Destination folder to put organized series files.') do |series_destination|
82
+ @options[:series_destination] = series_destination
83
+ end
88
84
 
89
- opts.on_tail('--accept-removing-all', :NONE, 'Accept removing source files. [NOT WORKING YET]') do
90
- @options[:accept_removing_all] = true
91
- end
85
+ opts.on_tail('-t', '--test', 'Test files name searching in media databases: only print results.') do
86
+ @options[:test] = true
87
+ end
92
88
 
93
- opts.on_tail("-?", "-h", "--help", "Show this message.") do
94
- puts opts
95
- exit
96
- end
89
+ opts.on_tail('--accept-removing-all', :NONE, 'Accept removing source files. [NOT WORKING YET]') do
90
+ @options[:accept_removing_all] = true
91
+ end
97
92
 
98
- opts.on_tail("-v", "--version", "Print version") do
99
- puts("Plexify #{VERSION}")
100
- exit
101
- end
102
-
103
- opts.on_tail('--trace', :NONE, 'Show a full traceback on error') do
104
- @options[:trace] = true
105
- end
106
- end
93
+ opts.on_tail("-?", "-h", "--help", "Show this message.") do
94
+ puts opts
95
+ exit
96
+ end
97
+
98
+ opts.on_tail("-v", "--version", "Print version") do
99
+ puts("Plexify #{VERSION}")
100
+ exit
101
+ end
107
102
 
108
- # Process result
109
- def process_result
103
+ opts.on_tail('--trace', :NONE, 'Show a full traceback on error') do
104
+ @options[:trace] = true
105
+ end
106
+ end
110
107
 
111
- Logger.info("=> Preparing source folder")
112
- source = Prepare::Source.new(@options)
113
- source.prepare
114
- Logger.info(" : #{source.files.size} #{source.files.size > 1 ? 'files' : 'file'} found")
108
+ # Process result
109
+ def process_result
115
110
 
116
- unless @options[:test]
117
- Logger.info("\n=> Preparing destination folder")
118
- destination = Prepare::Destination.new(@options)
119
- destination.prepare
120
- end
111
+ Logger.info("=> Preparing source folder")
112
+ source = Prepare::Source.new(@options)
113
+ source.prepare
114
+ Logger.info(" : #{source.files.size} #{source.files.size > 1 ? 'files' : 'file'} found")
115
+
116
+ unless @options[:test]
117
+ Logger.info("\n=> Preparing destination folder")
118
+ destination = Prepare::Destination.new(@options)
119
+ destination.prepare
120
+ end
121
121
 
122
- media_manager = MediaManager.new
123
- media_organizer = MediaOrganizer.new(source, destination) unless @options[:test]
124
-
125
- files_processed_count = 0
126
-
127
- # Process files
128
- for file in source.files
129
- basename = File.basename(file.path)
130
- Logger.info("\n\n=> Analyzing '#{basename}' file...")
131
- medias = media_manager.analyze(file)
132
-
133
- # Choose the good media
134
- if medias.any?
135
- Logger.info("\nFound medias :")
136
-
137
- # If the test argument is present, don't move files or prompt the user
138
- if @options[:test]
139
- for media in medias
140
- Logger.success("\n#{media.data.name} #{media.data.released ? "(#{Date.parse(media.data.released).year})" : nil}")
141
- end
142
- else
143
- Logger.success("\n0: The movie isn't in the list, go next without doing anything.")
144
- medias.each_with_index do |media, index|
145
- Logger.success("\n#{index+1}: #{media.data.name} #{media.data.released ? "(#{Date.parse(media.data.released).year})" : nil}")
146
- end
147
-
148
- Logger.success("\nChoose the movie: ")
149
- resp = STDIN.gets.chomp.to_i-1
150
-
151
- if resp >= 0 && resp <= medias.size
152
- media = medias[resp]
153
- Logger.success("\nMedia found : #{media.data.name} #{media.data.released ? "(#{Date.parse(media.data.released).year})" : nil}")
154
- media_organizer.move_to_destination(file, media)
155
- files_processed_count += 1
156
- elsif resp == -1
157
- Logger.info("Aborting...")
158
- next
159
- end
160
- end
161
- else
162
- Logger.error("\nMedia not found")
163
- end
122
+ media_manager = MediaManager.new
123
+ media_organizer = MediaOrganizer.new(source, destination) unless @options[:test]
124
+
125
+ files_processed_count = 0
126
+
127
+ # Process files
128
+ for file in source.files
129
+ basename = File.basename(file.path)
130
+ Logger.info("\n\n=> Analyzing '#{basename}' file...")
131
+ medias = media_manager.analyze(file)
132
+
133
+ # Choose the good media
134
+ if medias.any?
135
+
136
+ # If the test argument is present, don't move files or prompt the user
137
+ if @options[:test]
138
+ Logger.info("\nFound medias :")
139
+
140
+ for media in medias
141
+ Logger.success("\n#{media.data.name} #{media.data.released ? "(#{Date.parse(media.data.released).year})" : nil}")
142
+ end
143
+ else
144
+ Logger.success("\nThe movie is '#{medias.first.data.name} #{medias.first.data.released ? "(#{Date.parse(medias.first.data.released).year})" : nil}'. Right ? (y/n) ")
145
+ resp = STDIN.gets.chomp
146
+
147
+ if resp.eql?("y")
148
+
149
+ media_organizer.move_to_destination(file, medias.first)
150
+ files_processed_count += 1
151
+ else
152
+ Logger.success("\n0: The movie isn't in the list, go next without doing anything.")
153
+ medias.each_with_index do |media, index|
154
+ Logger.success("\n#{index+1}: #{media.data.name} #{media.data.released ? "(#{Date.parse(media.data.released).year})" : nil}")
164
155
  end
165
156
 
166
- Logger.info("\n\n=> Files pocessed #{files_processed_count}/#{source.files.size}") unless @options[:test]
157
+ Logger.success("\nChoose the movie: ")
158
+ resp = STDIN.gets.chomp.to_i-1
159
+
160
+ if resp >= 0 && resp <= medias.size
161
+ media = medias[resp]
162
+ Logger.success("\nMedia found : #{media.data.name} #{media.data.released ? "(#{Date.parse(media.data.released).year})" : nil}")
163
+ media_organizer.move_to_destination(file, media)
164
+ files_processed_count += 1
165
+ elsif resp == -1
166
+ Logger.info("Aborting...")
167
+ next
168
+ end
169
+ end
167
170
  end
171
+ else
172
+ Logger.error("\nMedia not found")
173
+ end
168
174
  end
175
+
176
+ Logger.info("\n\n=> Files pocessed #{files_processed_count}/#{source.files.size}") unless @options[:test]
177
+ end
169
178
  end
179
+ end
170
180
  end
@@ -1,19 +1,19 @@
1
1
  module Plexify
2
- # Logger class
3
- class Logger
4
- # print informations
5
- def self.info(content)
6
- print content
7
- end
2
+ # Logger class
3
+ class Logger
4
+ # print informations
5
+ def self.info(content)
6
+ print content
7
+ end
8
8
 
9
- # print success in green
10
- def self.success(content)
11
- print content.colorize(:green)
12
- end
9
+ # print success in green
10
+ def self.success(content)
11
+ print content.colorize(:green)
12
+ end
13
13
 
14
- # print errors in red
15
- def self.error(content)
16
- print content.colorize(:red)
17
- end
14
+ # print errors in red
15
+ def self.error(content)
16
+ print content.colorize(:red)
18
17
  end
18
+ end
19
19
  end
data/lib/plexify/media.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  module Plexify
2
- # Media class
3
- # Will include more methods to test media data
4
- class Media
5
- attr_accessor :data
6
- attr_accessor :found_title
7
- attr_accessor :score
2
+ # Media class
3
+ # Will include more methods to test media data
4
+ class Media
5
+ attr_accessor :data
6
+ attr_accessor :found_title
7
+ attr_accessor :score
8
8
 
9
- def initialize(data)
10
- @data = data
11
- end
9
+ def initialize(data)
10
+ @data = data
12
11
  end
12
+ end
13
13
  end
@@ -1,88 +1,106 @@
1
1
  module Plexify
2
- class MediaManager
3
- # Initialize variables and load tmdb media manager
4
- def initialize
5
- @tmdb_api_key = nil
6
- @tmdb_default_language = nil
7
- load_tmdb
8
- end
9
-
10
- # Search for a media in the Tmdb media manager database.
11
- def analyze(file)
12
- name = File.basename(file.path, File.extname(file.path))
13
- splitted_name = name.split(/\W/).map(&:downcase)
2
+ class MediaManager
3
+ include Amatch
14
4
 
15
- medias = analyse_names(splitted_name, {})
5
+ # Initialize variables and load tmdb media manager
6
+ def initialize
7
+ @tmdb_api_key = nil
8
+ @tmdb_default_language = nil
9
+ load_tmdb
10
+ end
16
11
 
17
- flattened_medias = []
18
- medias.each_pair do |title, media|
19
- flattened_medias << media if flattened_medias.empty?
20
- unless flattened_medias.map(&:data).map(&:id).include?(media.data.id)
21
- media.found_title = title
22
- flattened_medias << media
23
- end
24
- end
12
+ # Search for a media in the Tmdb media manager database.
13
+ def analyze(file)
14
+ name = File.basename(file.path, File.extname(file.path))
15
+ splitted_name = name.split(/\W/).map(&:downcase)
16
+ found_medias = analyze_names(splitted_name, {})
25
17
 
26
- return flattened_medias
18
+ medias = Array.new
19
+ found_medias.each_pair do |title, list|
20
+ for media in list
21
+ medias << media if medias.empty?
22
+ unless medias.map(&:data).map(&:id).include?(media.data.id)
23
+ media.found_title = title
24
+ medias << media
25
+ end
27
26
  end
27
+ end
28
28
 
29
- private
30
- # Load tmdb media manager
31
- def load_tmdb
32
- load_plexify_config
33
- Tmdb.api_key = @tmdb_api_key
34
- Tmdb.default_language = @tmdb_default_language
35
- end
29
+ # Check differences betweend the file title
30
+ # and found medias names
31
+ title = name.gsub(/\W/, " ").downcase
32
+ for media in medias
33
+ name = media.data.name.downcase
34
+ media.score = title.hamming_similar(name)
35
+ end
36
36
 
37
- # Load plexify config yaml file in the home directory
38
- # The file structure is :
39
- # plexify:
40
- # tmdb:
41
- # api_key: xxxx
42
- # default_language: en
43
- def load_plexify_config
44
- config_file_path = File.join(File.dirname(__FILE__), "../../.plexify.yml")
45
- config_file = File.open config_file_path
46
- yaml_config = YAML::load(config_file)
47
-
48
- tmdb_config = yaml_config["plexify"]["tmdb"]
49
- @tmdb_api_key = tmdb_config["api_key"]
50
- @tmdb_default_language = tmdb_config["default_language"]
51
- end
37
+ # Compare title with original media name
38
+ # if the score is better, it selects it
39
+ for media in medias
40
+ name = media.data.original_name.downcase
41
+ score = title.hamming_similar(name)
42
+ media.score = score if score > media.score
43
+ end
52
44
 
53
- def analyse_names(list, medias)
54
- title = String.new
45
+ # Return ten last medias sort by score
46
+ return medias.sort_by(&:score).reverse.delete_if {|m| medias.index(m) > 10 }
47
+ end
55
48
 
56
- list.each_with_index do |str, index|
57
- title << " " if title.length > 0
58
- title << str
59
- media = find(title)
49
+ private
50
+ # Load tmdb media manager
51
+ def load_tmdb
52
+ load_plexify_config
53
+ Tmdb.api_key = @tmdb_api_key
54
+ Tmdb.default_language = @tmdb_default_language
55
+ end
60
56
 
61
- if media.empty?
62
- if medias.any?
63
- shift = list.shift
64
- analyse_names(list, medias)
65
- end
66
- else
67
- medias[title] = Media.new(media)
68
- end
69
- end
70
- return medias
71
- end
57
+ # Load plexify config yaml file in the home directory
58
+ # The file structure is :
59
+ # plexify:
60
+ # tmdb:
61
+ # api_key: xxxx
62
+ # default_language: en
63
+ def load_plexify_config
64
+ config_file_path = File.join(File.dirname(__FILE__), "../../.plexify.yml")
65
+ config_file = File.open config_file_path
66
+ yaml_config = YAML::load(config_file)
72
67
 
73
- # Get Levenshtein distance
74
- def levenshtein_distance(first, second)
75
- Text::Levenshtein.distance(first, second)
76
- end
68
+ tmdb_config = yaml_config["plexify"]["tmdb"]
69
+ @tmdb_api_key = tmdb_config["api_key"]
70
+ @tmdb_default_language = tmdb_config["default_language"]
71
+ end
77
72
 
78
- # Find a movie in the Tmdb database with a title and a limit of one item
79
- def find(title)
80
- TmdbMovie.find(:title => title, :limit => 1)
81
- end
73
+ # Analyze title name: iterates each words and find a related media
74
+ def analyze_names(list, medias)
75
+ title = String.new
76
+
77
+ list.each_with_index do |str, index|
78
+ title << " " if title.length > 0
79
+ title << str
80
+ found_medias = find(title)
82
81
 
83
- # Find all movies in the Tmdb database with a title
84
- def find_all(title)
85
- TmdbMovie.find(:title => title)
82
+ if found_medias.empty?
83
+ if medias.any?
84
+ shift = list.shift
85
+ analyze_names(list, medias)
86
+ end
87
+ else
88
+ tmp_medias = Array.new
89
+ found_medias.each { |m| tmp_medias << Media.new(m) }
90
+ medias[title] = tmp_medias
86
91
  end
92
+ end
93
+ return medias
94
+ end
95
+
96
+ # Find a movie in the Tmdb database with a title and a limit of one item
97
+ def find(title)
98
+ TmdbMovie.find(:title => title, :limit => 5)
99
+ end
100
+
101
+ # Find all movies in the Tmdb database with a title
102
+ def find_all(title)
103
+ TmdbMovie.find(:title => title)
87
104
  end
105
+ end
88
106
  end
@@ -1,71 +1,71 @@
1
1
  module Plexify
2
- # Class MediaOrganizer
3
- # It manage source and destination folders
4
- class MediaOrganizer
5
- attr_reader :source
6
- attr_reader :destination
2
+ # Class MediaOrganizer
3
+ # It manage source and destination folders
4
+ class MediaOrganizer
5
+ attr_reader :source
6
+ attr_reader :destination
7
7
 
8
- # Initialize
9
- def initialize(source, destination)
10
- @source = source
11
- @destination = destination
12
- end
8
+ # Initialize
9
+ def initialize(source, destination)
10
+ @source = source
11
+ @destination = destination
12
+ end
13
13
 
14
- # Move a file the his appropriate destination folder
15
- def move_to_destination(file, media)
16
- # Consider media is a movie
17
- destination = @destination.movies_folder.path
14
+ # Move a file the his appropriate destination folder
15
+ def move_to_destination(file, media)
16
+ # Consider media is a movie
17
+ destination = @destination.movies_folder.path
18
18
 
19
- # Create an appropriate media folder
20
- media_folder_name = "#{media.data.name} (#{Date.parse(media.data.released).year})"
21
- media_folder_path = File.join(destination, media_folder_name)
22
- file_basename = File.basename(file.path)
19
+ # Create an appropriate media folder
20
+ media_folder_name = "#{media.data.name} (#{Date.parse(media.data.released).year})"
21
+ media_folder_path = File.join(destination, media_folder_name)
22
+ file_basename = File.basename(file.path)
23
23
 
24
- # Create the movie folder
25
- FileUtils.mkdir(media_folder_path) unless File.exists?(media_folder_path)
26
- media_folder = File.open(media_folder_path)
24
+ # Create the movie folder
25
+ FileUtils.mkdir(media_folder_path) unless File.exists?(media_folder_path)
26
+ media_folder = File.open(media_folder_path)
27
27
 
28
- if media_folder
29
- renamed_file_basename = media_folder_name + File.extname(file_basename)
30
- renamed_file_path = File.join(media_folder.path, renamed_file_basename)
28
+ if media_folder
29
+ renamed_file_basename = media_folder_name + File.extname(file_basename)
30
+ renamed_file_path = File.join(media_folder.path, renamed_file_basename)
31
31
 
32
- # Copy the file with a progress bar
33
- Logger.info("\nCopying file to '#{renamed_file_path}'")
34
- copy_with_progressbar(file.path, renamed_file_path)
35
- Logger.success("File '#{renamed_file_path}' copied") if File.exists?(renamed_file_path)
36
- end
32
+ # Copy the file with a progress bar
33
+ Logger.info("Copying file to '#{renamed_file_path}'")
34
+ copy_with_progressbar(file.path, renamed_file_path)
35
+ Logger.success("File '#{renamed_file_path}' copied") if File.exists?(renamed_file_path)
36
+ end
37
37
 
38
- Logger.info("\nDo you want to remove the source file '#{file_basename}' ? (y/n) ")
39
- resp = STDIN.gets.chomp
38
+ Logger.info("\nDo you want to remove the source file '#{file_basename}' ? (y/n) ")
39
+ resp = STDIN.gets.chomp
40
40
 
41
- if resp.eql?("y")
42
- FileUtils.rm file.path
43
- Logger.success("File '#{file_basename}' removed")
44
- end
45
- end
41
+ if resp.eql?("y")
42
+ FileUtils.rm file.path
43
+ Logger.success("File '#{file_basename}' removed")
44
+ end
45
+ end
46
46
 
47
- private
47
+ private
48
48
 
49
- # Copy a file with a great progress bar
50
- def copy_with_progressbar(source, destination)
51
- source_file = File.new(source, "r")
52
- destination_file = File.new(destination, "w")
53
- source_size = File.size(source)
54
- batch_bytes = ( source_size / 100 ).ceil
55
- total = 0
49
+ # Copy a file with a great progress bar
50
+ def copy_with_progressbar(source, destination)
51
+ source_file = File.new(source, "r")
52
+ destination_file = File.new(destination, "w")
53
+ source_size = File.size(source)
54
+ batch_bytes = ( source_size / 100 ).ceil
55
+ total = 0
56
56
 
57
- p_bar = ProgressBar.create(:title => "Copying '#{File.basename(source_file.path)}'", :format => '|%b>%i| %p%% %t')
58
- buffer = source_file.sysread(batch_bytes)
57
+ p_bar = ProgressBar.create(:title => "Copying '#{File.basename(destination_file.path)}'", :format => '|%b>%i| %p%% %t')
58
+ buffer = source_file.sysread(batch_bytes)
59
59
 
60
- while total < source_size do
61
- destination_file.syswrite(buffer)
62
- p_bar.progress = ((total*100)/source_size).ceil + 1
63
- total += batch_bytes
64
- if (source_size - total) < batch_bytes
65
- batch_bytes = (source_size - total)
66
- end
67
- buffer = source_file.sysread(batch_bytes)
68
- end
60
+ while total < source_size do
61
+ destination_file.syswrite(buffer)
62
+ p_bar.progress = ((total*100)/source_size).ceil + 1
63
+ total += batch_bytes
64
+ if (source_size - total) < batch_bytes
65
+ batch_bytes = (source_size - total)
69
66
  end
67
+ buffer = source_file.sysread(batch_bytes)
68
+ end
70
69
  end
70
+ end
71
71
  end
@@ -1,91 +1,91 @@
1
1
  module Plexify
2
- module Prepare
3
- # Destination class implementation
4
- class Destination
5
- attr_accessor :folder
6
- attr_accessor :movies_folder
7
- attr_accessor :series_folder
2
+ module Prepare
3
+ # Destination class implementation
4
+ class Destination
5
+ attr_accessor :folder
6
+ attr_accessor :movies_folder
7
+ attr_accessor :series_folder
8
8
 
9
- # Plexify::Execute initialize method
10
- def initialize(options)
11
- @destination_path = options[:destination]
12
- @movies_destination_path = options[:movies_destination]
13
- @series_destination_path = options[:series_destination]
14
- end
9
+ # Plexify::Execute initialize method
10
+ def initialize(options)
11
+ @destination_path = options[:destination]
12
+ @movies_destination_path = options[:movies_destination]
13
+ @series_destination_path = options[:series_destination]
14
+ end
15
15
 
16
- def prepare
17
- if @destination_path
18
- prepare_destination
19
- else
20
- prepare_destinations
21
- end
22
- end
23
-
24
- protected
25
- # Prepare destination
26
- def prepare_destination
27
- # Create destination folder
28
- destination_path = @destination_path
29
- @folder = create_or_use_folder(destination_path)
16
+ def prepare
17
+ if @destination_path
18
+ prepare_destination
19
+ else
20
+ prepare_destinations
21
+ end
22
+ end
30
23
 
31
- # Create "Movies" and "TV Shows" folder
32
- @movies_folder = create_or_use_folder(destination_path, "Movies")
33
- @series_folder = create_or_use_folder(destination_path, "TV Shows")
34
- end
24
+ protected
25
+ # Prepare destination
26
+ def prepare_destination
27
+ # Create destination folder
28
+ destination_path = @destination_path
29
+ @folder = create_or_use_folder(destination_path)
35
30
 
36
- # Prepare destinations
37
- def prepare_destinations
38
- # Create or use movies and series folders
39
- movies_path = @movies_destination_path
40
- series_path = @series_destination_path
31
+ # Create "Movies" and "TV Shows" folder
32
+ @movies_folder = create_or_use_folder(destination_path, "Movies")
33
+ @series_folder = create_or_use_folder(destination_path, "TV Shows")
34
+ end
41
35
 
42
- @movies_folder = create_or_use_folder(movies_path) if movies_path
43
- @series_folder = create_or_use_folder(series_path) if series_path
44
- end
36
+ # Prepare destinations
37
+ def prepare_destinations
38
+ # Create or use movies and series folders
39
+ movies_path = @movies_destination_path
40
+ series_path = @series_destination_path
45
41
 
46
- # Create or use a folder
47
- def create_or_use_folder(*args)
48
- path = args.first
42
+ @movies_folder = create_or_use_folder(movies_path) if movies_path
43
+ @series_folder = create_or_use_folder(series_path) if series_path
44
+ end
49
45
 
50
- if args.size > 1
51
- name = args[1]
52
- end
46
+ # Create or use a folder
47
+ def create_or_use_folder(*args)
48
+ path = args.first
53
49
 
54
- folder_path = name ? File.join(path, name) : path
50
+ if args.size > 1
51
+ name = args[1]
52
+ end
55
53
 
56
- if File.exists?(folder_path) && File.directory?(folder_path)
57
- folder = File.open(folder_path)
58
- else
59
- Logger.info("\n=> Created missing '#{name ? name : File.basename(folder_path)}' folder in destination folder.")
60
- FileUtils.mkdir_p folder_path
61
- folder = File.open(folder_path) if File.exists?(folder_path)
62
- end
54
+ folder_path = name ? File.join(path, name) : path
63
55
 
64
- folder
65
- end
56
+ if File.exists?(folder_path) && File.directory?(folder_path)
57
+ folder = File.open(folder_path)
58
+ else
59
+ Logger.info("\n=> Created missing '#{name ? name : File.basename(folder_path)}' folder in destination folder.")
60
+ FileUtils.mkdir_p folder_path
61
+ folder = File.open(folder_path) if File.exists?(folder_path)
66
62
  end
67
63
 
68
- # Source class implementation
69
- class Source
70
- attr_accessor :folder
71
- attr_accessor :files
72
-
73
- # Initialize
74
- def initialize(options)
75
- @source_path = options[:source]
76
- @files = Array.new
77
- end
64
+ folder
65
+ end
66
+ end
67
+
68
+ # Source class implementation
69
+ class Source
70
+ attr_accessor :folder
71
+ attr_accessor :files
72
+
73
+ # Initialize
74
+ def initialize(options)
75
+ @source_path = options[:source]
76
+ @files = Array.new
77
+ end
78
78
 
79
- # Prepare source folder
80
- def prepare
81
- @folder = File.new @source_path
79
+ # Prepare source folder
80
+ def prepare
81
+ @folder = File.new @source_path
82
82
 
83
- if File.exists?(@folder.path) && File.directory?(@folder.path)
84
- Dir.glob(@folder.path + "/**/*.{mkv,avi,mov}") do |file|
85
- @files << File.open(file)
86
- end
87
- end
88
- end
83
+ if File.exists?(@folder.path) && File.directory?(@folder.path)
84
+ Dir.glob(@folder.path + "/**/*.{mkv,avi,mov}") do |file|
85
+ @files << File.open(file)
86
+ end
89
87
  end
88
+ end
90
89
  end
90
+ end
91
91
  end
@@ -1,3 +1,3 @@
1
1
  module Plexify
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/plexify.gemspec CHANGED
@@ -14,9 +14,11 @@ Gem::Specification.new do |gem|
14
14
 
15
15
  gem.add_dependency("ruby-tmdb", "= 0.2.1")
16
16
  gem.add_dependency("colorize", "= 0.5.8")
17
- gem.add_dependency("text", "= 1.2.1")
17
+ gem.add_dependency("amatch", "= 0.2.10")
18
18
  gem.add_dependency("ruby-progressbar", "= 1.0.2")
19
19
 
20
+ gem.add_development_dependency 'rspec', '~> 2.12.0'
21
+
20
22
  gem.files = `git ls-files`.split($/)
21
23
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
22
24
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Plexify, "#Version" do
4
+ it 'should return correct version string' do
5
+ Plexify.version.should == "Plexify version #{Plexify::VERSION}"
6
+ end
7
+ end
8
+
9
+ describe Plexify, "#Arguments" do
10
+ it 'should raise an error by passing bad arguments count' do
11
+ #TODO
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'plexify'
4
+
5
+ RSpec.configure do |config|
6
+ config.color_enabled = true
7
+ config.formatter = 'documentation'
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plexify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-03 00:00:00.000000000 Z
12
+ date: 2012-12-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby-tmdb
@@ -44,13 +44,13 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: 0.5.8
46
46
  - !ruby/object:Gem::Dependency
47
- name: text
47
+ name: amatch
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
51
  - - '='
52
52
  - !ruby/object:Gem::Version
53
- version: 1.2.1
53
+ version: 0.2.10
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.2.1
61
+ version: 0.2.10
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: ruby-progressbar
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - '='
76
76
  - !ruby/object:Gem::Version
77
77
  version: 1.0.2
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 2.12.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 2.12.0
78
94
  description: Organize media folders to get ready with media managers
79
95
  email:
80
96
  - pfilstroff@gmail.com
@@ -99,6 +115,8 @@ files:
99
115
  - lib/plexify/prepare.rb
100
116
  - lib/plexify/version.rb
101
117
  - plexify.gemspec
118
+ - spec/plexify_spec.rb
119
+ - spec/spec_helper.rb
102
120
  homepage: ''
103
121
  licenses: []
104
122
  post_install_message:
@@ -123,4 +141,6 @@ rubygems_version: 1.8.24
123
141
  signing_key:
124
142
  specification_version: 3
125
143
  summary: Media managers files organizer
126
- test_files: []
144
+ test_files:
145
+ - spec/plexify_spec.rb
146
+ - spec/spec_helper.rb