motion_vj 0.1.0 → 0.2.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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OWUwMzVjNGM0YWFjMzEwNmMxMGJmMGZmOTlkMjA0MDVhMzBkNWFmMw==
4
+ NmUzNGIxZDY1ZjAwMDI4YTU5OTM2YWExMmFiZDAyODdmNGNkZDc0Mg==
5
5
  data.tar.gz: !binary |-
6
- MTgwODhmYzliNjRiNTM2MjBkNzdjZWQxODFiZDZkZTdkMGJjNTM3ZQ==
6
+ NTE5ZDViYTQ1ZGVjYjRkMDhiNGI0ZjUzYmNlMDg2YTY0ZWVjMjk0YQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MjJlMTEyM2I1MjM3NGYwODU3NTY5OGJmMTA2NjdlZjlhOTEwYmZmZjAzN2Q4
10
- YTcwZjczZGIzMzI0N2FiMmNiOGFhMjlkZjQ3MDMyZTc1OTI5Y2VmYzlkNGY1
11
- NDdiODljZjg5NmJjZGJjYzcwMWE4MTc0YmUxY2I1YTEwZmFkZWU=
9
+ MDA2NDQzMzFhMTQ3ODNjZTFkYTEyMGM5NWRlYjE2ZGE1MWY2NjI1NjU4MWQz
10
+ NmU1NjFkNGJjZTZkOWExOWE5Y2QxYWFlNjczNjgxZGIwMzIxYmQ2MGIwMGQ4
11
+ N2E1MTk1YjljYWQ1ZGIxNTQwYzdiNTE5ZmFiN2UyNjM5ZTFkMTA=
12
12
  data.tar.gz: !binary |-
13
- ZTQ0NWJiOGFkZGYxOThlNjQ3YTk0NGRkM2E5MTdhZGJjM2VjNTFhZWZlZjJm
14
- Mjg4Y2VjNjc0MjNlMzJlYmI3OTI5MWEzNjc2MTdkMGFlN2QwNGNjMjU3ZjIz
15
- YmY4MTQ3ODY4N2NlMGIzNDk5YWFhNWQ0ODUwNjE3NDdhODNmYzU=
13
+ NjU3Y2FlYjAzOTFjOGNiMjIyMzQ3N2FjNmJmM2U3MDQ1MmQ2NjJjM2M1NDAy
14
+ MjI2NmU3Y2Y3OTFlMzNkMjA4ODExYmY4OTk1ZTg4NWMwYTI4M2Y5NzljMWJh
15
+ M2U3ZTg0YmQzYWM3ODA1ODhiMWE0YzJkYmIzNDIwYzE4NWU1OTM=
data/README.md CHANGED
@@ -8,11 +8,40 @@ Install the gem and make the executable available:
8
8
 
9
9
  $ gem install motion_vj
10
10
 
11
+ ## Configuration
12
+
13
+ The configuration file should look like this:
14
+
15
+ ```yaml
16
+ # config.yml
17
+
18
+ # To obtain the app key and secret, go to https://www.dropbox.com/developers/apps/create
19
+ db_app_key: <App key from Dropbox>
20
+ db_app_secret: <App secret from Dropbox>
21
+ # The token can be generated using `--get-token`. Please see the Usage section of the README.
22
+ db_app_token: <App token from Dropbox>
23
+ # The Dropbox directory where the files will be uploaded.
24
+ db_videos_dir: /
25
+
26
+ # The motion CLI name.
27
+ motion_cmd: motion
28
+ # Path to the PID file that will be created when running.
29
+ pid_file: /var/run/motion/motion.pid
30
+ # Directory where motion save the videos.
31
+ videos_dir: /var/run/motion/videos
32
+ # Extension of the videos that should be uploaded.
33
+ videos_extension: avi
34
+ ```
35
+
36
+ You must provide it using the `--config-file` option as pointed by the [Usage](#usage) section.
37
+
11
38
  ## Usage
12
39
 
13
- Once installed, a Dropbox token is needed to start. Run `motionvj --get-token` and follow the instructions.
40
+ So that `motionvj` can access a Dropbox account, a Dropbox token needs to be created. This will be a one time action, and it can be acomplished running `motionvj --get-token --config-file config.yml`, where `config.yml` is the file detailed by the [Configuration](#configuration) section of this README. Once the token is created, it should be added to the same configuration file.
41
+
42
+ To start uploading new videos, just run `motionvj --config-file config.yml`. This should upload new videos that end with the extension indicated by the configuration file. After a file is uploaded to Dropbox, it is then deleted from the local filesystem.
14
43
 
15
- For more details, run `motionvj --help`:
44
+ For more options, run `motionvj --help`:
16
45
 
17
46
  ```
18
47
  Usage: motionvj [options]
@@ -2,26 +2,36 @@
2
2
 
3
3
  require 'motion_vj'
4
4
 
5
- require 'dotenv'
6
5
  require 'fileutils'
7
6
  require 'optparse'
7
+ require 'yaml'
8
8
 
9
9
  class App
10
- def self.parse!(argv)
11
- options = {}
10
+ attr_accessor :options, :config
11
+
12
+ def initialize(argv)
13
+ parse!(argv)
14
+ load_config!
15
+ start
16
+ end
17
+
18
+ private
19
+
20
+ def parse!(argv)
21
+ self.options = {}
12
22
  opt_parser = OptionParser.new do |opts|
13
23
  opts.banner = 'Usage: motionvj [options]'
14
24
 
15
25
  opts.separator 'Required:'
16
26
 
17
- opts.on('-c', '--config-file [CONFIG_FILE]', 'Path to the configuration file') do |config_filepath|
18
- options[:config_filepath] = config_filepath
27
+ opts.on('-c', '--config-file [CONFIG_YAML_FILE]', 'Path to the configuration YAML file') do |config_filepath|
28
+ self.options[:config_filepath] = config_filepath
19
29
  end
20
30
 
21
31
  opts.separator 'Optional:'
22
32
 
23
33
  opts.on('-t', '--get-token', 'Get the Dropbox token') do
24
- options[:get_token] = true
34
+ self.options[:get_token] = true
25
35
  end
26
36
 
27
37
  opts.separator 'Common:'
@@ -44,72 +54,70 @@ class App
44
54
  abort opt_parser.to_s
45
55
  end
46
56
 
47
- if options[:config_filepath].nil? || options[:config_filepath].to_s.strip.empty?
48
- $stderr.puts 'The configuration file is required.'
57
+ if self.options[:config_filepath].nil? || self.options[:config_filepath].to_s.strip.empty?
58
+ $stderr.puts 'The configuration YAML file is required.'
49
59
  abort opt_parser.to_s
50
60
  end
51
-
52
- options
53
61
  end
54
62
 
55
- def self.start(options)
56
- Dotenv.load(options[:config_filepath])
57
- self.check_config
63
+ def load_config!
64
+ self.config = YAML.load_file(self.options[:config_filepath])
65
+ blank_config_msg = %w( db_videos_dir motion_cmd pid_file videos_dir videos_extension ).map { |key|
66
+ key if /\A[[:space:]]*\z/ === self.config[key].to_s
67
+ }.compact
68
+ abort "The following configuration options are missing:\n#{ blank_config_msg.join("\n") }" unless blank_config_msg.empty?
69
+ rescue Errno::ENOENT
70
+ abort "Could not open the configuration file: #{ self.options[:config_filepath] }"
71
+ end
58
72
 
73
+ def start
59
74
  trap('INT') do
60
- self.remove_pid_file
75
+ remove_pid_file
61
76
  exit 2
62
77
  end
63
78
 
64
- self.create_pid_file
79
+ create_pid_file
65
80
 
66
81
  if options[:get_token]
67
- MotionVj.get_dropbox_token(self.get_env('DP_APP_KEY'), self.get_env('DP_APP_SECRET'))
82
+ MotionVj.get_dropbox_token(self.config['db_app_key'], self.config['db_app_secret'])
68
83
  else
69
- MotionVj.start(get_env('DP_APP_TOKEN'))
84
+ MotionVj.start(db_app_token: self.config['db_app_token'],
85
+ videos_dir: self.config['videos_dir'],
86
+ videos_extension: self.config['videos_extension'],
87
+ motion_cmd: self.config['motion_cmd'],
88
+ db_videos_dir: self.config['db_videos_dir'])
70
89
  sleep
71
90
  end
91
+ ensure
92
+ remove_pid_file
72
93
  end
73
94
 
74
- private
75
-
76
- def self.check_config
77
- %w( MOTION_CMD VIDEOS_DIR VIDEO_EXTENTION PID_FILE DB_VIDEOS_DIR ).each { |key| self.get_env(key) }
78
- end
79
-
80
- def self.get_env(key)
81
- value = ENV[key]
82
- abort "The environment variable '#{key}' is blank or defined." if value.to_s.strip.empty?
83
- value
84
- end
85
-
86
- def self.read_pid
95
+ def read_pid
87
96
  pid = nil
88
- if File.exist?(ENV['PID_FILE'])
89
- File.open(ENV['PID_FILE'], 'r') do |f|
97
+ if File.exist?(self.config['pid_file'])
98
+ File.open(self.config['pid_file'], 'r') do |f|
90
99
  pid = f.gets.to_i rescue nil
91
100
  end
92
101
  end
93
102
  pid
94
103
  end
95
104
 
96
- def self.create_pid_file
97
- pid = self.read_pid
105
+ def create_pid_file
106
+ pid = read_pid
98
107
  if pid && !pid.zero?
99
108
  pid_exist = !!Process.kill(0, pid) rescue false
100
- abort "motionvj is already running. Please check the PID in '#{ENV['PID_FILE']}'." if pid_exist
109
+ abort "motionvj is already running. Please check the PID in '#{ self.config['pid_file'] }'." if pid_exist
101
110
  end
102
111
 
103
- File.open(ENV['PID_FILE'], 'w') do |f|
112
+ File.open(self.config['pid_file'], 'w') do |f|
104
113
  f.puts Process.pid
105
114
  end
106
115
  end
107
116
 
108
- def self.remove_pid_file
109
- pid = self.read_pid
110
- FileUtils.rm_f(ENV['PID_FILE']) if pid && pid === Process.pid
117
+ def remove_pid_file
118
+ pid = read_pid
119
+ FileUtils.rm_f(self.config['pid_file']) if pid && pid === Process.pid
111
120
  end
112
121
  end
113
122
 
114
- options = App.parse!(ARGV)
115
- App.start(options)
123
+ App.new(ARGV)
@@ -9,20 +9,20 @@ require 'listen'
9
9
  module MotionVj
10
10
  def self.get_dropbox_token(app_key, app_secret)
11
11
  token = MotionVj::Client.get_token(app_key, app_secret)
12
- puts "Your Dropbox access token for this app is: #{token}"
12
+ puts "Your Dropbox access token for this app is: #{ token }"
13
13
  end
14
14
 
15
- def self.start(token)
16
- listener = Listen.to(ENV['VIDEOS_DIR'], only: /\.#{Regexp.escape ENV['VIDEO_EXTENTION']}$/) do |modified_filepaths, _, removed_filepaths|
15
+ def self.start(options)
16
+ listener = Listen.to(options[:videos_dir], only: /\.#{ Regexp.escape options[:videos_extension] }$/) do |modified_filepaths, _, removed_filepaths|
17
17
  # handle addded files
18
18
  unless modified_filepaths.empty?
19
- client = MotionVj::Client.new(token)
20
- motion_lsof = `lsof -c #{ENV['MOTION_CMD']}`
19
+ client = MotionVj::Client.new(options[:db_app_token], options[:db_videos_dir])
20
+ motion_lsof = `lsof -c #{ options[:motion_cmd] }`
21
21
 
22
22
  modified_filepaths.each do |filepath|
23
23
  file_basename = File.basename filepath
24
24
 
25
- if motion_lsof =~ /#{Regexp.escape file_basename}/
25
+ if motion_lsof =~ /#{ Regexp.escape(file_basename) }/
26
26
  Logger.error "Added file still in use."
27
27
  next
28
28
  end
@@ -32,12 +32,12 @@ module MotionVj
32
32
  begin
33
33
  if client.upload(filepath)
34
34
  FileUtils.rm_f(filepath)
35
- Logger.info "'#{file_basename}' was uploaded."
35
+ Logger.info "'#{ file_basename }' was uploaded."
36
36
  else
37
- Logger.error "Could not upload '#{file_basename}'."
37
+ Logger.error "Could not upload '#{ file_basename }'."
38
38
  end
39
39
  rescue => e
40
- Logger.error "Could not upload '#{file_basename}'."
40
+ Logger.error "Could not upload '#{ file_basename }'."
41
41
  end
42
42
  end
43
43
  end
@@ -45,7 +45,7 @@ module MotionVj
45
45
 
46
46
  # handle removed files
47
47
  removed_filepaths.each do |filepath|
48
- Logger.info "'#{File.basename(filepath)}' deleted."
48
+ Logger.info "'#{ File.basename(filepath) }' deleted."
49
49
  end
50
50
  end
51
51
  listener.start
@@ -2,15 +2,16 @@ require 'dropbox_sdk'
2
2
 
3
3
  module MotionVj
4
4
  class Client
5
- attr_reader :db_client
5
+ attr_reader :db_client, :videos_dir
6
6
 
7
- def initialize(token)
7
+ def initialize(token, videos_dir)
8
8
  @db_client = DropboxClient.new(token)
9
+ @videos_dir = videos_dir
9
10
  end
10
11
 
11
12
  def file_exist?(filename)
12
13
  begin
13
- metadata = db_client.metadata(File.join(ENV['DB_VIDEOS_DIR'], filename))
14
+ metadata = self.db_client.metadata(File.join(self.videos_dir, filename))
14
15
  metadata && !metadata['is_dir'] && metadata['bytes'] && metadata['bytes'] > 0
15
16
  rescue DropboxError => e
16
17
  false
@@ -19,7 +20,7 @@ module MotionVj
19
20
 
20
21
  def upload(filepath)
21
22
  open(filepath) do |file|
22
- metadata = db_client.put_file(File.join(ENV['DB_VIDEOS_DIR'], File.basename(filepath)), file, true)
23
+ metadata = self.db_client.put_file(File.join(self.videos_dir, File.basename(filepath)), file, true)
23
24
  metadata && !metadata['is_dir'] && metadata['bytes'] && metadata['bytes'] > 0
24
25
  end
25
26
  end
@@ -28,7 +29,7 @@ module MotionVj
28
29
  flow = DropboxOAuth2FlowNoRedirect.new(app_key, app_secret)
29
30
  authorize_url = flow.start
30
31
 
31
- puts "1. Go to: #{authorize_url}"
32
+ puts "1. Go to: #{ authorize_url }"
32
33
  puts '2. Click "Allow" (you might have to log in first)'
33
34
  puts '3. Copy the authorization code'
34
35
  print 'Enter the authorization code here: '
@@ -5,7 +5,7 @@ module MotionVj
5
5
  loop do
6
6
  value = $stdin.gets.to_s.strip
7
7
  if value.empty?
8
- print("Please provide a valid #{input_name}:")
8
+ print("Please provide a valid #{ input_name }: ")
9
9
  else
10
10
  return value
11
11
  end
@@ -11,7 +11,7 @@ module MotionVj
11
11
  private
12
12
 
13
13
  def self.format(msg, type)
14
- "[motionvj][#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S %Z")}][#{type}]: #{msg}"
14
+ "[motionvj][#{ Time.now.utc.strftime("%Y-%m-%d %H:%M:%S %Z") }][#{ type }]: #{ msg }"
15
15
  end
16
16
  end
17
17
  end
@@ -1,3 +1,3 @@
1
1
  module MotionVj
2
- VERSION = "0.1.0"
2
+ VERSION = '0.2.0'
3
3
  end
@@ -19,7 +19,6 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_dependency 'dotenv', "~> 2.0"
23
22
  spec.add_dependency 'dropbox-sdk', "~> 1.6"
24
23
  spec.add_dependency 'listen', "~> 3.0"
25
24
 
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion_vj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roque Pinel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-29 00:00:00.000000000 Z
11
+ date: 2016-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: dotenv
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ~>
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ~>
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: dropbox-sdk
29
15
  requirement: !ruby/object:Gem::Requirement