elch_scan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 131c629fe880ea13e446b157bc7586d7d0ebb780
4
+ data.tar.gz: 986cd909e6034a135cd68a523860139daa6689c3
5
+ SHA512:
6
+ metadata.gz: 7b002be74cadb78eb3c2dc5758d09f863b24b57b652dd8e470e6875a5dc01b70c989938066210444380cd6a498d98406a2cf27efd5356deab943a4c5eea88926
7
+ data.tar.gz: c6b3ec97796266ff9eb171307972eaec59cb124fd6151edd7a1bc117accd4e587d70e1e82475302beb914abf3b0630975308250c05387dcd340d38a35bf933f6
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elch_scan.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sven Pachnit
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.
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # ElchScan
2
+
3
+ Query your MediaElch/XBMC library with Ruby! Easy and powerful search for your media chaos.
4
+
5
+ * Query on NFO, source data or file contents
6
+ * e.g.: List movies with actor X but not actor Y and release date was between 2003 and 2010
7
+ * e.g.: List movies with or without local trailers
8
+ * e.g.: List movies with more than one or exactly one audio stream
9
+
10
+ ## Installation
11
+
12
+ $ gem install elch_scan
13
+
14
+ ## Usage
15
+
16
+ First generate a sample configuration by running
17
+
18
+ $ elch_scan --generate-config
19
+
20
+ You will need to specify at least one directory with movies in it. You might want to change other settings as well.
21
+
22
+
23
+ To get a basic list of what you've got run
24
+
25
+ $ elch_scan -q
26
+
27
+ ![example](http://files.sven.bmonkeys.net/images/_master_Volumescodebinelch_scan__bash_20140408_072644_20140408_072649.png)
28
+
29
+ To get a list of available options run
30
+
31
+ $ elch_scan --help
32
+
33
+ Usage: elch_scan [options]
34
+ --generate-config Generate sample configuration file in ~/.elch_scan.yml
35
+ -h, --help Shows this help
36
+ -v, --version Shows version and other info
37
+ -f, --formatter HTML Use formatter
38
+ -o, --output FILENAME Write formatted results to file
39
+ -e, --edit SELECT_SCRIPT Edit selector script
40
+ -s, --select [WITH_SUBS,NO_NFO] Filter movies with saved selector scripts
41
+ -p, --permute Open editor to write permutation code for collection
42
+ -q, --quiet Don't ask to filter or save results
43
+ -c, --console Start console to play around with the collection
44
+
45
+ If you choose to create a script or filter on the fly you will find some more examples on this topic.
46
+
47
+ ### Filters
48
+
49
+ You can easily filter your movies with Ruby. It's not hard, just look at these examples.
50
+
51
+ ```ruby
52
+ # Filter by name, for regex see http://rubular.com
53
+ collection.select! {|name, movie| movie.name =~ /simpsons/i }
54
+
55
+ # Rating > 5
56
+ collection.select! {|name, movie| movie.nfo!{|n| n["rating"].first.to_f > 5 } }
57
+
58
+ # 720p or higher
59
+ collection.select! { |name, movie| movie.source.width >= 1280 }
60
+
61
+ # With actor
62
+ collection.select! do |name, movie|
63
+ movie.nfo! {|n| n["actor"].map {|actor| actor["name"].first }.include?("Jim Carrey") }
64
+ end
65
+ ```
66
+
67
+ Note: Use `binding.pry` to start an interactive console so you can easily check out which attributes are available.
68
+
69
+ ### Custom formatters
70
+
71
+ To add a custom formatter just add the ruby file to your config (you can omit the .rb):
72
+
73
+ ```yml
74
+ formatters:
75
+ - "~/.elch_scan/my_custom_formatter.rb"
76
+ ```
77
+
78
+ To write a custom formatter look at the existing ones. You can take this as template:
79
+
80
+ ```ruby
81
+ module ElchScan
82
+ module Formatter
83
+ class MyFormatter < Base
84
+
85
+ def format(results)
86
+ [].tap do |lines|
87
+ # render your output and append it to lines
88
+ lines << "I have #{results.count} results here..."
89
+ binding.pry # Interactive console will start here!
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
96
+ ```
97
+
98
+ You can then use your formatter by passing `-f MyFormatter`, it's case sensitive!
99
+
100
+
101
+ ## ToDo
102
+
103
+ - [ ] Add HTML formatter
104
+ - [ ] Add support for TV shows
105
+
106
+ ## Contributing
107
+
108
+ 1. Fork it ( http://github.com/2called-chaos/elch_scan/fork )
109
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
110
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
111
+ 4. Push to the branch (`git push origin my-new-feature`)
112
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/elch_scan ADDED
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ # That's __FILE__ in BASH :)
4
+ # From: http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in
5
+ SOURCE="${BASH_SOURCE[0]}"
6
+ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
7
+ MCLDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
8
+ SOURCE="$(readlink "$SOURCE")"
9
+ [[ $SOURCE != /* ]] && SOURCE="$MCLDIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
10
+ done
11
+ PROJECT_ROOT="$( cd -P "$( dirname "$SOURCE" )"/.. && pwd )"
12
+
13
+ # Actually run Heatmon
14
+ cd $PROJECT_ROOT && bundle exec ruby elch_scan.rb "$@"
data/doc/config.yml ADDED
@@ -0,0 +1,44 @@
1
+ # This file has to be valid YAML!
2
+ # Small howto: http://ess.khhq.net/wiki/YAML_Tutorial
3
+ # Validate: http://yamllint.com/
4
+
5
+ # add your movie directories here. Note that we only support
6
+ # "one folder per movie" structures. TV show support may come soon.
7
+ movies:
8
+ - "/mnt/media/my_movies"
9
+
10
+ # if you want to add custom formatters you can pass a list of ruby files.
11
+ # take a look at the existing formatters to build your own.
12
+ formatters: []
13
+
14
+ # Application settings
15
+ application:
16
+ # Checks for new version when calling "--version" or "-v"
17
+ check_version: true
18
+
19
+ # The command of the editor to use for defining filters
20
+ # - vim
21
+ # - nano
22
+ # - mate -w
23
+ # - subl -w
24
+ editor: vim
25
+
26
+ # Change these to match your file naming
27
+ naming:
28
+ nfo: <baseFileName>.nfo
29
+ poster: <baseFileName>-poster.jpg
30
+ fanart: <baseFileName>-fanart.jpg
31
+ logo: logo.png
32
+ clear_art: clearart.png
33
+ cd_art: disc.png
34
+ banner: <baseFileName>-banner.jpg
35
+ thumb: <baseFileName>-landscape.jpg
36
+ trailer: <baseFileName>-trailer
37
+
38
+ # used to determine whether a file is a video file or not
39
+ video_extensions: 3gp avi flv m1v m2v m4v mkv mov mpeg mpg mpe ogg rm wmv
40
+
41
+ # This controls the console output and logging
42
+ logger:
43
+ # disable colorized output
44
+ colorize: true
data/doc/filter.rb ADDED
@@ -0,0 +1,70 @@
1
+ # TIP: Using vim and want to get rid of this example shit?
2
+ # In nav-mode type: 100dd
3
+
4
+ # Hey there,
5
+ # to filter your records you will use Ruby
6
+ # but don't be afraid, it's fairly simple.
7
+ # Just look at the examples and referenced links.
8
+
9
+ # You have access to a variable `collection` and
10
+ # whatever you do with it, we will take the same
11
+ # variable `collection` as result.
12
+ # This means you can reassign or permute it.
13
+ # YOU SHOULD NOT MODIFY the movie objects! Do this
14
+ # with "-p" or "--permute"!
15
+
16
+ # Use ruby methods to narrow down you result set.
17
+ # * http://www.ruby-doc.org/core-2.1.1/File.html
18
+ # * http://www.ruby-doc.org/core-2.1.1/Enumerable.html
19
+
20
+ # ====================================================
21
+ # = Doc (remove, reuse or comment out the examples!) =
22
+ # ====================================================
23
+ collection.select! do |name, movie|
24
+ # name is the same as movie.dirname
25
+ # movie has the following methods
26
+ # * dir => source movie directory (e.g. C:/Movies)
27
+ # * path => folder path of movie (e.g. C:/Movies/BestFilmEver)
28
+ # * dirname => source movie directory name (e.g. BestFilmEver)
29
+ # * files => array of all files in movie folder
30
+ # * name => base name of movie file (without extension)
31
+ # * movie => movie file
32
+ # * nfo! => Hash/Array representation of NFO-XML (see http://xml-simple.rubyforge.org/)
33
+ # Almost all shit is an array so [0] or .first is your friend.
34
+ # Pass a block (yields the nfo representation) to catch nil[] errors.
35
+ # * source => StreamIO object (see https://github.com/streamio/streamio-ffmpeg)
36
+ # * all naming key names from the configuration file (nfo, poster, etc.)
37
+
38
+ # Set break point to interactively call methods from here.
39
+ # See http://pryrepl.org ory type "help" when you are in the REPL.
40
+ # Use exit or exit! to break out of REPL.
41
+ # binding.pry
42
+ end
43
+
44
+ # Filter by name, for regex see http://rubular.com
45
+ collection.select! {|name, movie| movie.name =~ /simpsons/i }
46
+
47
+ # Rating > 5
48
+ collection.select! {|name, movie| movie.nfo!{|n| n["rating"].first.to_f > 5 } }
49
+
50
+ # 720p or higher
51
+ collection.select! { |name, movie| movie.source.width >= 1280 }
52
+
53
+ # With actor
54
+ collection.select! do |name, movie|
55
+ movie.nfo! {|n| n["actor"].map {|actor| actor["name"].first }.include?("Jim Carrey") }
56
+ end
57
+
58
+ # No thriller movies
59
+ collection.select! do |name, movie|
60
+ !movie.nfo!{|n| n["genre"][0].split("/").map(&:strip).include?("Thriller") }
61
+ end
62
+
63
+ # Only with english sound stream
64
+ collection.select! do |name, movie|
65
+ movie.nfo! do |nfo|
66
+ nfo["fileinfo"][0]["streamdetails"][0]["audio"].any? do |stream|
67
+ stream["language"][0] == "eng"
68
+ end
69
+ end
70
+ end
data/elch_scan.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elch_scan/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "elch_scan"
8
+ spec.version = ElchScan::VERSION
9
+ spec.authors = ["Sven Pachnit"]
10
+ spec.email = ["sven@bmonkeys.net"]
11
+ spec.summary = %q{ODO: Write a short summary. Required.}
12
+ spec.description = %q{ODO: Write a longer description. Optional.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "active_support"
22
+ spec.add_runtime_dependency "i18n"
23
+ spec.add_runtime_dependency "pry"
24
+ spec.add_runtime_dependency "xml-simple"
25
+ spec.add_runtime_dependency "streamio-ffmpeg"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.5"
28
+ spec.add_development_dependency "rake"
29
+ end
data/elch_scan.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "elch_scan"
2
+ ElchScan::Application.dispatch(ENV, ARGV)
@@ -0,0 +1,182 @@
1
+ require 'active_support/core_ext/big_decimal/conversions'
2
+ require 'active_support/core_ext/object/blank'
3
+ require 'active_support/core_ext/hash/keys'
4
+ require 'active_support/i18n'
5
+ require 'active_support/core_ext/class/attribute'
6
+
7
+ module ActiveSupport
8
+ module NumberHelper
9
+ class NumberConverter # :nodoc:
10
+ # Default and i18n option namespace per class
11
+ class_attribute :namespace
12
+
13
+ # Does the object need a number that is a valid float?
14
+ class_attribute :validate_float
15
+
16
+ attr_reader :number, :opts
17
+
18
+ DEFAULTS = {
19
+ # Used in number_to_delimited
20
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
21
+ format: {
22
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
23
+ separator: ".",
24
+ # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
25
+ delimiter: ",",
26
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
27
+ precision: 3,
28
+ # If set to true, precision will mean the number of significant digits instead
29
+ # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
30
+ significant: false,
31
+ # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
32
+ strip_insignificant_zeros: false
33
+ },
34
+
35
+ # Used in number_to_currency
36
+ currency: {
37
+ format: {
38
+ format: "%u%n",
39
+ negative_format: "-%u%n",
40
+ unit: "$",
41
+ # These five are to override number.format and are optional
42
+ separator: ".",
43
+ delimiter: ",",
44
+ precision: 2,
45
+ significant: false,
46
+ strip_insignificant_zeros: false
47
+ }
48
+ },
49
+
50
+ # Used in number_to_percentage
51
+ percentage: {
52
+ format: {
53
+ delimiter: "",
54
+ format: "%n%"
55
+ }
56
+ },
57
+
58
+ # Used in number_to_rounded
59
+ precision: {
60
+ format: {
61
+ delimiter: ""
62
+ }
63
+ },
64
+
65
+ # Used in number_to_human_size and number_to_human
66
+ human: {
67
+ format: {
68
+ # These five are to override number.format and are optional
69
+ delimiter: "",
70
+ precision: 3,
71
+ significant: true,
72
+ strip_insignificant_zeros: true
73
+ },
74
+ # Used in number_to_human_size
75
+ storage_units: {
76
+ # Storage units output formatting.
77
+ # %u is the storage unit, %n is the number (default: 2 MB)
78
+ format: "%n %u",
79
+ units: {
80
+ byte: "Bytes",
81
+ kb: "KB",
82
+ mb: "MB",
83
+ gb: "GB",
84
+ tb: "TB"
85
+ }
86
+ },
87
+ # Used in number_to_human
88
+ decimal_units: {
89
+ format: "%n %u",
90
+ # Decimal units output formatting
91
+ # By default we will only quantify some of the exponents
92
+ # but the commented ones might be defined or overridden
93
+ # by the user.
94
+ units: {
95
+ # femto: Quadrillionth
96
+ # pico: Trillionth
97
+ # nano: Billionth
98
+ # micro: Millionth
99
+ # mili: Thousandth
100
+ # centi: Hundredth
101
+ # deci: Tenth
102
+ unit: "",
103
+ # ten:
104
+ # one: Ten
105
+ # other: Tens
106
+ # hundred: Hundred
107
+ thousand: "Thousand",
108
+ million: "Million",
109
+ billion: "Billion",
110
+ trillion: "Trillion",
111
+ quadrillion: "Quadrillion"
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ def self.convert(number, options)
118
+ new(number, options).execute
119
+ end
120
+
121
+ def initialize(number, options)
122
+ @number = number
123
+ @opts = options.symbolize_keys
124
+ end
125
+
126
+ def execute
127
+ if !number
128
+ nil
129
+ elsif validate_float? && !valid_float?
130
+ number
131
+ else
132
+ convert
133
+ end
134
+ end
135
+
136
+ private
137
+
138
+ def options
139
+ @options ||= format_options.merge(opts)
140
+ end
141
+
142
+ def format_options #:nodoc:
143
+ default_format_options.merge!(i18n_format_options)
144
+ end
145
+
146
+ def default_format_options #:nodoc:
147
+ options = DEFAULTS[:format].dup
148
+ options.merge!(DEFAULTS[namespace][:format]) if namespace
149
+ options
150
+ end
151
+
152
+ def i18n_format_options #:nodoc:
153
+ locale = opts[:locale]
154
+ options = I18n.translate(:'number.format', locale: locale, default: {}).dup
155
+
156
+ if namespace
157
+ options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {}))
158
+ end
159
+
160
+ options
161
+ end
162
+
163
+ def translate_number_value_with_default(key, i18n_options = {}) #:nodoc:
164
+ I18n.translate(key, { default: default_value(key), scope: :number }.merge!(i18n_options))
165
+ end
166
+
167
+ def translate_in_locale(key, i18n_options = {})
168
+ translate_number_value_with_default(key, { locale: options[:locale] }.merge(i18n_options))
169
+ end
170
+
171
+ def default_value(key)
172
+ key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
173
+ end
174
+
175
+ def valid_float? #:nodoc:
176
+ Float(number)
177
+ rescue ArgumentError, TypeError
178
+ false
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveSupport
2
+ module NumberHelper
3
+ class NumberToDelimitedConverter < NumberConverter #:nodoc:
4
+ self.validate_float = true
5
+
6
+ DELIMITED_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
7
+
8
+ def convert
9
+ parts.join(options[:separator])
10
+ end
11
+
12
+ private
13
+
14
+ def parts
15
+ left, right = number.to_s.split('.')
16
+ left.gsub!(DELIMITED_REGEX) { "#{$1}#{options[:delimiter]}" }
17
+ [left, right].compact
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ module ActiveSupport
2
+ module NumberHelper
3
+ class NumberToHumanSizeConverter < NumberConverter #:nodoc:
4
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb]
5
+
6
+ self.namespace = :human
7
+ self.validate_float = true
8
+
9
+ def convert
10
+ @number = Float(number)
11
+
12
+ # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
13
+ unless options.key?(:strip_insignificant_zeros)
14
+ options[:strip_insignificant_zeros] = true
15
+ end
16
+
17
+ if smaller_than_base?
18
+ number_to_format = number.to_i.to_s
19
+ else
20
+ human_size = number / (base ** exponent)
21
+ number_to_format = NumberToRoundedConverter.convert(human_size, options)
22
+ end
23
+ conversion_format.gsub(/%n/, number_to_format).gsub(/%u/, unit)
24
+ end
25
+
26
+ private
27
+
28
+ def conversion_format
29
+ translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true)
30
+ end
31
+
32
+ def unit
33
+ translate_number_value_with_default(storage_unit_key, :locale => options[:locale], :count => number.to_i, :raise => true)
34
+ end
35
+
36
+ def storage_unit_key
37
+ key_end = smaller_than_base? ? 'byte' : STORAGE_UNITS[exponent]
38
+ "human.storage_units.units.#{key_end}"
39
+ end
40
+
41
+ def exponent
42
+ max = STORAGE_UNITS.size - 1
43
+ exp = (Math.log(number) / Math.log(base)).to_i
44
+ exp = max if exp > max # avoid overflow for the highest unit
45
+ exp
46
+ end
47
+
48
+ def smaller_than_base?
49
+ number.to_i < base
50
+ end
51
+
52
+ def base
53
+ opts[:prefix] == :si ? 1000 : 1024
54
+ end
55
+ end
56
+ end
57
+ end
58
+