motion_vj 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +31 -2
- data/exe/motionvj +49 -41
- data/lib/motion_vj.rb +10 -10
- data/lib/motion_vj/client.rb +6 -5
- data/lib/motion_vj/helpers/input.rb +1 -1
- data/lib/motion_vj/logger.rb +1 -1
- data/lib/motion_vj/version.rb +1 -1
- data/motion_vj.gemspec +0 -1
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NmUzNGIxZDY1ZjAwMDI4YTU5OTM2YWExMmFiZDAyODdmNGNkZDc0Mg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTE5ZDViYTQ1ZGVjYjRkMDhiNGI0ZjUzYmNlMDg2YTY0ZWVjMjk0YQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MDA2NDQzMzFhMTQ3ODNjZTFkYTEyMGM5NWRlYjE2ZGE1MWY2NjI1NjU4MWQz
|
10
|
+
NmU1NjFkNGJjZTZkOWExOWE5Y2QxYWFlNjczNjgxZGIwMzIxYmQ2MGIwMGQ4
|
11
|
+
N2E1MTk1YjljYWQ1ZGIxNTQwYzdiNTE5ZmFiN2UyNjM5ZTFkMTA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
44
|
+
For more options, run `motionvj --help`:
|
16
45
|
|
17
46
|
```
|
18
47
|
Usage: motionvj [options]
|
data/exe/motionvj
CHANGED
@@ -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
|
-
|
11
|
-
|
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 [
|
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
|
56
|
-
|
57
|
-
|
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
|
-
|
75
|
+
remove_pid_file
|
61
76
|
exit 2
|
62
77
|
end
|
63
78
|
|
64
|
-
|
79
|
+
create_pid_file
|
65
80
|
|
66
81
|
if options[:get_token]
|
67
|
-
MotionVj.get_dropbox_token(self.
|
82
|
+
MotionVj.get_dropbox_token(self.config['db_app_key'], self.config['db_app_secret'])
|
68
83
|
else
|
69
|
-
MotionVj.start(
|
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
|
-
|
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?(
|
89
|
-
File.open(
|
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
|
97
|
-
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 '#{
|
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(
|
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
|
109
|
-
pid =
|
110
|
-
FileUtils.rm_f(
|
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
|
-
|
115
|
-
App.start(options)
|
123
|
+
App.new(ARGV)
|
data/lib/motion_vj.rb
CHANGED
@@ -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(
|
16
|
-
listener = Listen.to(
|
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(
|
20
|
-
motion_lsof = `lsof -c #{
|
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
|
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
|
data/lib/motion_vj/client.rb
CHANGED
@@ -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(
|
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(
|
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: '
|
data/lib/motion_vj/logger.rb
CHANGED
data/lib/motion_vj/version.rb
CHANGED
data/motion_vj.gemspec
CHANGED
@@ -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.
|
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-
|
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
|