elch_scan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+