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 +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
|