danta 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +102 -0
- data/bin/danta +5 -0
- data/lib/danta/api.rb +17 -0
- data/lib/danta/app.rb +20 -0
- data/lib/danta/dispatcher.rb +90 -0
- data/lib/danta/library/node.rb +57 -0
- data/lib/danta/library/null_node.rb +31 -0
- data/lib/danta/library/tree.rb +85 -0
- data/lib/danta/public/css/bootstrap-treeview.min.css +1 -0
- data/lib/danta/public/css/danta.css +15 -0
- data/lib/danta/public/index.html +49 -0
- data/lib/danta/public/js/bootstrap-treeview.min.js +1 -0
- data/lib/danta/public/js/danta.js +22 -0
- data/lib/danta/public/js/jquery-2.1.4.min.js +4 -0
- data/lib/danta/public/js/jquery.mobile.custom.min.js +3 -0
- data/lib/danta/public/js/player_actions.js +62 -0
- data/lib/danta/public/js/player_modal.js +16 -0
- data/lib/danta/public/js/response_dispatcher.js +26 -0
- data/lib/danta/public/js/video_library.js +45 -0
- data/lib/danta/public/js/video_tree.js +22 -0
- data/lib/danta/public/js/videos_response.js +14 -0
- data/lib/danta/public/js/web_socket_client.js +62 -0
- data/lib/danta/public/ws.html +50 -0
- data/lib/danta/request_handler.rb +50 -0
- data/lib/danta/root.rb +44 -0
- data/lib/danta/version.rb +3 -0
- data/lib/danta/video_library.rb +63 -0
- data/lib/danta.rb +3 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 04256810a41ebae351de08e5a2d03e45813eddf5
|
4
|
+
data.tar.gz: 6c8275981d760bbde30eaeee46c5f638b11a3300
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a8b52d0972003071f25444929a0af4f4ea07b72141d6a2962dd70e940dba61337cd11ee95961d9109e9bc9a796809b9fc456cbd24a8e63e0e640e9e4eda41cf8
|
7
|
+
data.tar.gz: b1f0432b0d712234d80705b5f02a65584d98ca8fc036b7b088bca83d7131dcf2ec025b8310d8dcd32736e01a3c1a292e72d12797990c3def6b09a067ca3af214
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Carlos Chacon
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Danta
|
2
|
+
Danta is a web app for easy video playing in your Raspberry Pi.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
### Install ruby
|
7
|
+
|
8
|
+
We're going to use [RVM](https://rvm.io/rvm/install) to install Ruby.
|
9
|
+
|
10
|
+
```
|
11
|
+
\curl -sSL https://get.rvm.io | bash -s stable --ruby
|
12
|
+
```
|
13
|
+
|
14
|
+
### Install xdotool and omxplayer
|
15
|
+
|
16
|
+
Danta uses [Pecari](https://github.com/caedocha/pecari) to play videos, so install the following packages:
|
17
|
+
|
18
|
+
```
|
19
|
+
sudo apt-get install xdotool omxplayer
|
20
|
+
```
|
21
|
+
|
22
|
+
### Add Video Library file
|
23
|
+
|
24
|
+
Danta needs to know where is your video library. Add a `video_library.yml` file in the home directory.
|
25
|
+
|
26
|
+
```
|
27
|
+
cd ~
|
28
|
+
vim video_library.yml # Add your video library path here.
|
29
|
+
```
|
30
|
+
|
31
|
+
With the following data:
|
32
|
+
|
33
|
+
```
|
34
|
+
--
|
35
|
+
videos:
|
36
|
+
- '/path/to/videos/directory/'
|
37
|
+
|
38
|
+
```
|
39
|
+
|
40
|
+
### Install Danta gem
|
41
|
+
|
42
|
+
```
|
43
|
+
gem install danta
|
44
|
+
```
|
45
|
+
|
46
|
+
## Start Danta
|
47
|
+
|
48
|
+
Just call the danta command and the app will be ready to use.
|
49
|
+
|
50
|
+
```
|
51
|
+
danta
|
52
|
+
```
|
53
|
+
|
54
|
+
Access it with your smartphone's browser using the RPi's IP address. This is mine, for example:
|
55
|
+
|
56
|
+
```
|
57
|
+
192.168.1.10:9292
|
58
|
+
```
|
59
|
+
|
60
|
+
### Danta Environment Variables
|
61
|
+
|
62
|
+
Danta's behavior can be customized with the following environment variables:
|
63
|
+
|
64
|
+
```
|
65
|
+
DANTA_HOST # Overrides the default host, 0.0.0.0
|
66
|
+
DANTA_PORT # Overrides the default port, 9292
|
67
|
+
DANTA_VIDEO_LIBRARY # Overrides the default video library directory, the current user's home directory (~)
|
68
|
+
```
|
69
|
+
|
70
|
+
Examples:
|
71
|
+
|
72
|
+
```
|
73
|
+
export DANTA_HOST=localhost
|
74
|
+
export DANTA_PORT=9999
|
75
|
+
export DANTA_VIDEO_LIBRARY=/Other/video/library/directory
|
76
|
+
```
|
77
|
+
|
78
|
+
## Starting Danta at boot
|
79
|
+
|
80
|
+
Probably, you want to have Danta starting during boot time. In order to do this, edit the `rc.local` file:
|
81
|
+
|
82
|
+
```
|
83
|
+
sudo vim /etc/rc.local
|
84
|
+
```
|
85
|
+
|
86
|
+
Add the following line at the end of the file:
|
87
|
+
|
88
|
+
```
|
89
|
+
danta &
|
90
|
+
```
|
91
|
+
|
92
|
+
Save, exit and reboot the RPi.
|
93
|
+
|
94
|
+
## Supported Formats
|
95
|
+
|
96
|
+
Danta only supports `mkv`, `mov` and `mp4` videos. Any other video type is filtered out.
|
97
|
+
|
98
|
+
For more information, check [Pecari Usage Guide](https://github.com/caedocha/pecari#usage)
|
99
|
+
|
100
|
+
## Contact
|
101
|
+
|
102
|
+
You can send me an email to caedo.00 at gmail dot com. All feedback or questions are welcomed.
|
data/bin/danta
ADDED
data/lib/danta/api.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'sinatra-websocket'
|
3
|
+
require_relative 'request_handler'
|
4
|
+
|
5
|
+
module Danta
|
6
|
+
|
7
|
+
class Api < Sinatra::Base
|
8
|
+
|
9
|
+
get '/ws' do
|
10
|
+
RequestHandler.new(request: request).process
|
11
|
+
end
|
12
|
+
|
13
|
+
run! if __FILE__ == $0
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/lib/danta/app.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Danta
|
2
|
+
|
3
|
+
class App < Sinatra::Base
|
4
|
+
|
5
|
+
set :status, true
|
6
|
+
set :public_folder, public_dir
|
7
|
+
|
8
|
+
get '/' do
|
9
|
+
send_file(File.join(public_dir, 'index.html'))
|
10
|
+
end
|
11
|
+
|
12
|
+
def public_dir
|
13
|
+
File.join(File.dirname(__FILE__), 'public')
|
14
|
+
end
|
15
|
+
|
16
|
+
run! if __FILE__ == $0
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pecari'
|
3
|
+
require_relative 'video_library'
|
4
|
+
|
5
|
+
class Dispatcher
|
6
|
+
|
7
|
+
attr_reader :raw_data
|
8
|
+
|
9
|
+
def initialize(raw_data:)
|
10
|
+
@raw_data = raw_data
|
11
|
+
end
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
case action
|
15
|
+
when 'videos'
|
16
|
+
videos_response
|
17
|
+
when 'launch'
|
18
|
+
launch_action
|
19
|
+
when 'exec'
|
20
|
+
exec_action
|
21
|
+
else
|
22
|
+
unrecognized_response
|
23
|
+
end
|
24
|
+
rescue StandardError => e
|
25
|
+
invalid_response(e)
|
26
|
+
end
|
27
|
+
|
28
|
+
def videos_response
|
29
|
+
{
|
30
|
+
action: action,
|
31
|
+
status: 'success',
|
32
|
+
data: Danta::VideoLibrary.new.videos.to_json
|
33
|
+
}.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
def launch_action
|
37
|
+
Pecari::Player.launch(CGI.unescape(params['video']))
|
38
|
+
launch_response
|
39
|
+
end
|
40
|
+
|
41
|
+
def launch_response
|
42
|
+
{
|
43
|
+
action: action,
|
44
|
+
status: 'success',
|
45
|
+
data: "playing #{params['video']}"
|
46
|
+
}.to_json
|
47
|
+
end
|
48
|
+
|
49
|
+
def exec_action
|
50
|
+
Pecari::Player.send(params['command'])
|
51
|
+
exec_response
|
52
|
+
end
|
53
|
+
|
54
|
+
def exec_response
|
55
|
+
{
|
56
|
+
action: action,
|
57
|
+
status: 'success',
|
58
|
+
data: "executing #{params['command']}"
|
59
|
+
}.to_json
|
60
|
+
end
|
61
|
+
|
62
|
+
def unrecognized_response
|
63
|
+
{
|
64
|
+
action: unrecognized_action,
|
65
|
+
status: 'fail',
|
66
|
+
data: ''
|
67
|
+
}.to_json
|
68
|
+
end
|
69
|
+
|
70
|
+
def invalid_response(exception)
|
71
|
+
{
|
72
|
+
action: 'invalid_action',
|
73
|
+
status: 'fail',
|
74
|
+
data: exception.message
|
75
|
+
}.to_json
|
76
|
+
end
|
77
|
+
|
78
|
+
def data
|
79
|
+
@data ||= JSON.parse(raw_data)
|
80
|
+
end
|
81
|
+
|
82
|
+
def action
|
83
|
+
@action ||= data['action']
|
84
|
+
end
|
85
|
+
|
86
|
+
def params
|
87
|
+
@params ||= data['params']
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Library
|
4
|
+
|
5
|
+
class Node
|
6
|
+
|
7
|
+
attr_accessor :name
|
8
|
+
attr_accessor :nodes
|
9
|
+
attr_accessor :path
|
10
|
+
attr_accessor :parent
|
11
|
+
|
12
|
+
def initialize(name:, parent: nil, nodes: [])
|
13
|
+
@name = name
|
14
|
+
@nodes = nodes
|
15
|
+
@parent = parent
|
16
|
+
end
|
17
|
+
|
18
|
+
def root?
|
19
|
+
parent.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def leaf?
|
23
|
+
nodes.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_h
|
27
|
+
{
|
28
|
+
name: name,
|
29
|
+
path: path,
|
30
|
+
nodes: nodes.map(&:to_h)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_json
|
35
|
+
to_h.to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
def path
|
39
|
+
@path ||= build_path
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def build_path
|
45
|
+
next_parent = parent
|
46
|
+
parent_paths = [name]
|
47
|
+
while next_parent
|
48
|
+
parent_paths << next_parent.name
|
49
|
+
next_parent = next_parent.parent
|
50
|
+
end
|
51
|
+
parent_paths.reverse.join('/')
|
52
|
+
File.join(['/', parent_paths.reverse].flatten)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Library
|
2
|
+
|
3
|
+
class NullNode
|
4
|
+
|
5
|
+
def name
|
6
|
+
"nodeless"
|
7
|
+
end
|
8
|
+
|
9
|
+
def root?
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
def leaf?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_h
|
18
|
+
{}
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json
|
22
|
+
to_h.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
''
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative 'node'
|
2
|
+
require_relative 'null_node'
|
3
|
+
|
4
|
+
module Library
|
5
|
+
|
6
|
+
class Tree
|
7
|
+
|
8
|
+
attr_reader :nodes
|
9
|
+
attr_accessor :paths
|
10
|
+
|
11
|
+
def initialize(paths:)
|
12
|
+
@paths = paths
|
13
|
+
end
|
14
|
+
|
15
|
+
def nodes
|
16
|
+
@nodes ||= root_nodes
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
nodes.map(&:to_h)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_json
|
24
|
+
to_h.to_json
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def splitted_paths
|
30
|
+
paths.map { |path| path.split('/').reject { |path| path.empty? } }
|
31
|
+
end
|
32
|
+
|
33
|
+
def unlinked_nodes
|
34
|
+
@unlinked_nodes ||= splitted_paths
|
35
|
+
.map do |paths|
|
36
|
+
paths.map do |path|
|
37
|
+
Node.new(name: path)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def linked_nodes
|
43
|
+
@linked_nodes ||= unlinked_nodes.map do |unlinked_nodes|
|
44
|
+
root_nodes = []
|
45
|
+
unlinked_nodes.each_cons(2).each_with_index do |(parent, child), index|
|
46
|
+
if(index == 0)
|
47
|
+
root_nodes << parent
|
48
|
+
end
|
49
|
+
child.parent = parent
|
50
|
+
parent.nodes << child
|
51
|
+
end
|
52
|
+
root_nodes
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def root_nodes
|
57
|
+
backup_nodes = linked_nodes.dup
|
58
|
+
temp_nodes = backup_nodes.first.dup
|
59
|
+
backup_nodes.shift
|
60
|
+
backup_nodes.each_with_object(temp_nodes) do |nod, tmp|
|
61
|
+
rewire_nodes(node: nod.first, base_node: tmp.first)
|
62
|
+
end
|
63
|
+
temp_nodes
|
64
|
+
end
|
65
|
+
|
66
|
+
def rewire_nodes(node:, base_node:, backup_parent: nil)
|
67
|
+
if(node.name == base_node.name)
|
68
|
+
x = base_node.nodes.detect { |n| n.name == node.nodes.first.name } || base_node.nodes.first || NullNode.new
|
69
|
+
if x.name == "nodeless"
|
70
|
+
rewire_nodes(node: node.nodes.first, base_node: x, backup_parent: base_node)
|
71
|
+
else
|
72
|
+
rewire_nodes(node: node.nodes.first, base_node: x)
|
73
|
+
end
|
74
|
+
elsif(base_node.name == "nodeless")
|
75
|
+
node.parent = backup_parent
|
76
|
+
backup_parent.nodes << node
|
77
|
+
else
|
78
|
+
node.parent = base_node.parent
|
79
|
+
base_node.parent.nodes << node
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
.treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{width:12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Danta Video Player</title>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
7
|
+
<link rel="stylesheet" href="css/bootstrap-treeview.min.css">
|
8
|
+
<link rel="stylesheet" href="css/danta.css">
|
9
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
10
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
11
|
+
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>
|
12
|
+
<script src="js/bootstrap-treeview.min.js"></script>
|
13
|
+
<script src="js/web_socket_client.js"></script>
|
14
|
+
<script src="js/response_dispatcher.js"></script>
|
15
|
+
<script src="js/videos_response.js"></script>
|
16
|
+
<script src="js/video_tree.js"></script>
|
17
|
+
<script src="js/video_library.js"></script>
|
18
|
+
<script src="js/player_actions.js"></script>
|
19
|
+
<script src="js/player_modal.js"></script>
|
20
|
+
<script src="js/danta.js"></script>
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
<div class="container">
|
24
|
+
<h1>Danta Video Player</h1>
|
25
|
+
<div id="tree"></div>
|
26
|
+
<div id="player" class="modal" role="dialog">
|
27
|
+
<div class="modal-dialog">
|
28
|
+
<div class="modal-content">
|
29
|
+
<div class="modal-header">
|
30
|
+
Player
|
31
|
+
</div>
|
32
|
+
<div class="modal-body">
|
33
|
+
<div id="controls">
|
34
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.play()"><span class="glyphicon glyphicon-play"></span></button>
|
35
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.pause()"><span class="glyphicon glyphicon-pause"></span></button>
|
36
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.fastBackward()"><span class="glyphicon glyphicon-fast-backward"></span></button>
|
37
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.fastForward()"><span class="glyphicon glyphicon-fast-forward"></span></button>
|
38
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.mute()"><span class="glyphicon glyphicon-volume-off"></span></button>
|
39
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.turnVolumeDown()"><span class="glyphicon glyphicon-volume-down"></span></button>
|
40
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.turnVolumeUp()"><span class="glyphicon glyphicon-volume-up"></span></button>
|
41
|
+
<button type="button" class="btn btn-default btn-lg" onclick="playerActions.quit()"><span class="glyphicon glyphicon-off"></span></button>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
</body>
|
49
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
!function(a,b,c,d){"use strict";var e="treeview",f={};f.settings={injectStyle:!0,levels:2,expandIcon:"glyphicon glyphicon-plus",collapseIcon:"glyphicon glyphicon-minus",emptyIcon:"glyphicon",nodeIcon:"",selectedIcon:"",checkedIcon:"glyphicon glyphicon-check",uncheckedIcon:"glyphicon glyphicon-unchecked",color:d,backColor:d,borderColor:d,onhoverColor:"#F5F5F5",selectedColor:"#FFFFFF",selectedBackColor:"#428bca",searchResultColor:"#D9534F",searchResultBackColor:d,enableLinks:!1,highlightSelected:!0,highlightSearchResults:!0,showBorder:!0,showIcon:!0,showCheckbox:!1,showTags:!1,multiSelect:!1,onNodeChecked:d,onNodeCollapsed:d,onNodeDisabled:d,onNodeEnabled:d,onNodeExpanded:d,onNodeSelected:d,onNodeUnchecked:d,onNodeUnselected:d,onSearchComplete:d,onSearchCleared:d},f.options={silent:!1,ignoreChildren:!1},f.searchOptions={ignoreCase:!0,exactMatch:!1,revealResults:!0};var g=function(b,c){return this.$element=a(b),this.elementId=b.id,this.styleId=this.elementId+"-style",this.init(c),{options:this.options,init:a.proxy(this.init,this),remove:a.proxy(this.remove,this),getNode:a.proxy(this.getNode,this),getParent:a.proxy(this.getParent,this),getSiblings:a.proxy(this.getSiblings,this),getSelected:a.proxy(this.getSelected,this),getUnselected:a.proxy(this.getUnselected,this),getExpanded:a.proxy(this.getExpanded,this),getCollapsed:a.proxy(this.getCollapsed,this),getChecked:a.proxy(this.getChecked,this),getUnchecked:a.proxy(this.getUnchecked,this),getDisabled:a.proxy(this.getDisabled,this),getEnabled:a.proxy(this.getEnabled,this),selectNode:a.proxy(this.selectNode,this),unselectNode:a.proxy(this.unselectNode,this),toggleNodeSelected:a.proxy(this.toggleNodeSelected,this),collapseAll:a.proxy(this.collapseAll,this),collapseNode:a.proxy(this.collapseNode,this),expandAll:a.proxy(this.expandAll,this),expandNode:a.proxy(this.expandNode,this),toggleNodeExpanded:a.proxy(this.toggleNodeExpanded,this),revealNode:a.proxy(this.revealNode,this),checkAll:a.proxy(this.checkAll,this),checkNode:a.proxy(this.checkNode,this),uncheckAll:a.proxy(this.uncheckAll,this),uncheckNode:a.proxy(this.uncheckNode,this),toggleNodeChecked:a.proxy(this.toggleNodeChecked,this),disableAll:a.proxy(this.disableAll,this),disableNode:a.proxy(this.disableNode,this),enableAll:a.proxy(this.enableAll,this),enableNode:a.proxy(this.enableNode,this),toggleNodeDisabled:a.proxy(this.toggleNodeDisabled,this),search:a.proxy(this.search,this),clearSearch:a.proxy(this.clearSearch,this)}};g.prototype.init=function(b){this.tree=[],this.nodes=[],b.data&&("string"==typeof b.data&&(b.data=a.parseJSON(b.data)),this.tree=a.extend(!0,[],b.data),delete b.data),this.options=a.extend({},f.settings,b),this.destroy(),this.subscribeEvents(),this.setInitialStates({nodes:this.tree},0),this.render()},g.prototype.remove=function(){this.destroy(),a.removeData(this,e),a("#"+this.styleId).remove()},g.prototype.destroy=function(){this.initialized&&(this.$wrapper.remove(),this.$wrapper=null,this.unsubscribeEvents(),this.initialized=!1)},g.prototype.unsubscribeEvents=function(){this.$element.off("click"),this.$element.off("nodeChecked"),this.$element.off("nodeCollapsed"),this.$element.off("nodeDisabled"),this.$element.off("nodeEnabled"),this.$element.off("nodeExpanded"),this.$element.off("nodeSelected"),this.$element.off("nodeUnchecked"),this.$element.off("nodeUnselected"),this.$element.off("searchComplete"),this.$element.off("searchCleared")},g.prototype.subscribeEvents=function(){this.unsubscribeEvents(),this.$element.on("click",a.proxy(this.clickHandler,this)),"function"==typeof this.options.onNodeChecked&&this.$element.on("nodeChecked",this.options.onNodeChecked),"function"==typeof this.options.onNodeCollapsed&&this.$element.on("nodeCollapsed",this.options.onNodeCollapsed),"function"==typeof this.options.onNodeDisabled&&this.$element.on("nodeDisabled",this.options.onNodeDisabled),"function"==typeof this.options.onNodeEnabled&&this.$element.on("nodeEnabled",this.options.onNodeEnabled),"function"==typeof this.options.onNodeExpanded&&this.$element.on("nodeExpanded",this.options.onNodeExpanded),"function"==typeof this.options.onNodeSelected&&this.$element.on("nodeSelected",this.options.onNodeSelected),"function"==typeof this.options.onNodeUnchecked&&this.$element.on("nodeUnchecked",this.options.onNodeUnchecked),"function"==typeof this.options.onNodeUnselected&&this.$element.on("nodeUnselected",this.options.onNodeUnselected),"function"==typeof this.options.onSearchComplete&&this.$element.on("searchComplete",this.options.onSearchComplete),"function"==typeof this.options.onSearchCleared&&this.$element.on("searchCleared",this.options.onSearchCleared)},g.prototype.setInitialStates=function(b,c){if(b.nodes){c+=1;var d=b,e=this;a.each(b.nodes,function(a,b){b.nodeId=e.nodes.length,b.parentId=d.nodeId,b.hasOwnProperty("selectable")||(b.selectable=!0),b.state=b.state||{},b.state.hasOwnProperty("checked")||(b.state.checked=!1),b.state.hasOwnProperty("disabled")||(b.state.disabled=!1),b.state.hasOwnProperty("expanded")||(!b.state.disabled&&c<e.options.levels&&b.nodes&&b.nodes.length>0?b.state.expanded=!0:b.state.expanded=!1),b.state.hasOwnProperty("selected")||(b.state.selected=!1),e.nodes.push(b),b.nodes&&e.setInitialStates(b,c)})}},g.prototype.clickHandler=function(b){this.options.enableLinks||b.preventDefault();var c=a(b.target),d=this.findNode(c);if(d&&!d.state.disabled){var e=c.attr("class")?c.attr("class").split(" "):[];-1!==e.indexOf("expand-icon")?(this.toggleExpandedState(d,f.options),this.render()):-1!==e.indexOf("check-icon")?(this.toggleCheckedState(d,f.options),this.render()):(d.selectable?this.toggleSelectedState(d,f.options):this.toggleExpandedState(d,f.options),this.render())}},g.prototype.findNode=function(a){var b=a.closest("li.list-group-item").attr("data-nodeid"),c=this.nodes[b];return c||console.log("Error: node does not exist"),c},g.prototype.toggleExpandedState=function(a,b){a&&this.setExpandedState(a,!a.state.expanded,b)},g.prototype.setExpandedState=function(b,c,d){c!==b.state.expanded&&(c&&b.nodes?(b.state.expanded=!0,d.silent||this.$element.trigger("nodeExpanded",a.extend(!0,{},b))):c||(b.state.expanded=!1,d.silent||this.$element.trigger("nodeCollapsed",a.extend(!0,{},b)),b.nodes&&!d.ignoreChildren&&a.each(b.nodes,a.proxy(function(a,b){this.setExpandedState(b,!1,d)},this))))},g.prototype.toggleSelectedState=function(a,b){a&&this.setSelectedState(a,!a.state.selected,b)},g.prototype.setSelectedState=function(b,c,d){c!==b.state.selected&&(c?(this.options.multiSelect||a.each(this.findNodes("true","g","state.selected"),a.proxy(function(a,b){this.setSelectedState(b,!1,d)},this)),b.state.selected=!0,d.silent||this.$element.trigger("nodeSelected",a.extend(!0,{},b))):(b.state.selected=!1,d.silent||this.$element.trigger("nodeUnselected",a.extend(!0,{},b))))},g.prototype.toggleCheckedState=function(a,b){a&&this.setCheckedState(a,!a.state.checked,b)},g.prototype.setCheckedState=function(b,c,d){c!==b.state.checked&&(c?(b.state.checked=!0,d.silent||this.$element.trigger("nodeChecked",a.extend(!0,{},b))):(b.state.checked=!1,d.silent||this.$element.trigger("nodeUnchecked",a.extend(!0,{},b))))},g.prototype.setDisabledState=function(b,c,d){c!==b.state.disabled&&(c?(b.state.disabled=!0,this.setExpandedState(b,!1,d),this.setSelectedState(b,!1,d),this.setCheckedState(b,!1,d),d.silent||this.$element.trigger("nodeDisabled",a.extend(!0,{},b))):(b.state.disabled=!1,d.silent||this.$element.trigger("nodeEnabled",a.extend(!0,{},b))))},g.prototype.render=function(){this.initialized||(this.$element.addClass(e),this.$wrapper=a(this.template.list),this.injectStyle(),this.initialized=!0),this.$element.empty().append(this.$wrapper.empty()),this.buildTree(this.tree,0)},g.prototype.buildTree=function(b,c){if(b){c+=1;var d=this;a.each(b,function(b,e){for(var f=a(d.template.item).addClass("node-"+d.elementId).addClass(e.state.checked?"node-checked":"").addClass(e.state.disabled?"node-disabled":"").addClass(e.state.selected?"node-selected":"").addClass(e.searchResult?"search-result":"").attr("data-nodeid",e.nodeId).attr("style",d.buildStyleOverride(e)),g=0;c-1>g;g++)f.append(d.template.indent);var h=[];if(e.nodes?(h.push("expand-icon"),h.push(e.state.expanded?d.options.collapseIcon:d.options.expandIcon)):h.push(d.options.emptyIcon),f.append(a(d.template.icon).addClass(h.join(" "))),d.options.showIcon){var h=["node-icon"];h.push(e.icon||d.options.nodeIcon),e.state.selected&&(h.pop(),h.push(e.selectedIcon||d.options.selectedIcon||e.icon||d.options.nodeIcon)),f.append(a(d.template.icon).addClass(h.join(" ")))}if(d.options.showCheckbox){var h=["check-icon"];h.push(e.state.checked?d.options.checkedIcon:d.options.uncheckedIcon),f.append(a(d.template.icon).addClass(h.join(" ")))}return f.append(d.options.enableLinks?a(d.template.link).attr("href",e.href).append(e.text):e.text),d.options.showTags&&e.tags&&a.each(e.tags,function(b,c){f.append(a(d.template.badge).append(c))}),d.$wrapper.append(f),e.nodes&&e.state.expanded&&!e.state.disabled?d.buildTree(e.nodes,c):void 0})}},g.prototype.buildStyleOverride=function(a){if(a.state.disabled)return"";var b=a.color,c=a.backColor;return this.options.highlightSelected&&a.state.selected&&(this.options.selectedColor&&(b=this.options.selectedColor),this.options.selectedBackColor&&(c=this.options.selectedBackColor)),this.options.highlightSearchResults&&a.searchResult&&!a.state.disabled&&(this.options.searchResultColor&&(b=this.options.searchResultColor),this.options.searchResultBackColor&&(c=this.options.searchResultBackColor)),"color:"+b+";background-color:"+c+";"},g.prototype.injectStyle=function(){this.options.injectStyle&&!c.getElementById(this.styleId)&&a('<style type="text/css" id="'+this.styleId+'"> '+this.buildStyle()+" </style>").appendTo("head")},g.prototype.buildStyle=function(){var a=".node-"+this.elementId+"{";return this.options.color&&(a+="color:"+this.options.color+";"),this.options.backColor&&(a+="background-color:"+this.options.backColor+";"),this.options.showBorder?this.options.borderColor&&(a+="border:1px solid "+this.options.borderColor+";"):a+="border:none;",a+="}",this.options.onhoverColor&&(a+=".node-"+this.elementId+":not(.node-disabled):hover{background-color:"+this.options.onhoverColor+";}"),this.css+a},g.prototype.template={list:'<ul class="list-group"></ul>',item:'<li class="list-group-item"></li>',indent:'<span class="indent"></span>',icon:'<span class="icon"></span>',link:'<a href="#" style="color:inherit;"></a>',badge:'<span class="badge"></span>'},g.prototype.css=".treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{width:12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}",g.prototype.getNode=function(a){return this.nodes[a]},g.prototype.getParent=function(a){var b=this.identifyNode(a);return this.nodes[b.parentId]},g.prototype.getSiblings=function(a){var b=this.identifyNode(a),c=this.getParent(b),d=c?c.nodes:this.tree;return d.filter(function(a){return a.nodeId!==b.nodeId})},g.prototype.getSelected=function(){return this.findNodes("true","g","state.selected")},g.prototype.getUnselected=function(){return this.findNodes("false","g","state.selected")},g.prototype.getExpanded=function(){return this.findNodes("true","g","state.expanded")},g.prototype.getCollapsed=function(){return this.findNodes("false","g","state.expanded")},g.prototype.getChecked=function(){return this.findNodes("true","g","state.checked")},g.prototype.getUnchecked=function(){return this.findNodes("false","g","state.checked")},g.prototype.getDisabled=function(){return this.findNodes("true","g","state.disabled")},g.prototype.getEnabled=function(){return this.findNodes("false","g","state.disabled")},g.prototype.selectNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setSelectedState(a,!0,b)},this)),this.render()},g.prototype.unselectNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setSelectedState(a,!1,b)},this)),this.render()},g.prototype.toggleNodeSelected=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.toggleSelectedState(a,b)},this)),this.render()},g.prototype.collapseAll=function(b){var c=this.findNodes("true","g","state.expanded");this.forEachIdentifier(c,b,a.proxy(function(a,b){this.setExpandedState(a,!1,b)},this)),this.render()},g.prototype.collapseNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setExpandedState(a,!1,b)},this)),this.render()},g.prototype.expandAll=function(b){if(b=a.extend({},f.options,b),b&&b.levels)this.expandLevels(this.tree,b.levels,b);else{var c=this.findNodes("false","g","state.expanded");this.forEachIdentifier(c,b,a.proxy(function(a,b){this.setExpandedState(a,!0,b)},this))}this.render()},g.prototype.expandNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setExpandedState(a,!0,b),a.nodes&&b&&b.levels&&this.expandLevels(a.nodes,b.levels-1,b)},this)),this.render()},g.prototype.expandLevels=function(b,c,d){d=a.extend({},f.options,d),a.each(b,a.proxy(function(a,b){this.setExpandedState(b,c>0?!0:!1,d),b.nodes&&this.expandLevels(b.nodes,c-1,d)},this))},g.prototype.revealNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){for(var c=this.getParent(a);c;)this.setExpandedState(c,!0,b),c=this.getParent(c)},this)),this.render()},g.prototype.toggleNodeExpanded=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.toggleExpandedState(a,b)},this)),this.render()},g.prototype.checkAll=function(b){var c=this.findNodes("false","g","state.checked");this.forEachIdentifier(c,b,a.proxy(function(a,b){this.setCheckedState(a,!0,b)},this)),this.render()},g.prototype.checkNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setCheckedState(a,!0,b)},this)),this.render()},g.prototype.uncheckAll=function(b){var c=this.findNodes("true","g","state.checked");this.forEachIdentifier(c,b,a.proxy(function(a,b){this.setCheckedState(a,!1,b)},this)),this.render()},g.prototype.uncheckNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setCheckedState(a,!1,b)},this)),this.render()},g.prototype.toggleNodeChecked=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.toggleCheckedState(a,b)},this)),this.render()},g.prototype.disableAll=function(b){var c=this.findNodes("false","g","state.disabled");this.forEachIdentifier(c,b,a.proxy(function(a,b){this.setDisabledState(a,!0,b)},this)),this.render()},g.prototype.disableNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setDisabledState(a,!0,b)},this)),this.render()},g.prototype.enableAll=function(b){var c=this.findNodes("true","g","state.disabled");this.forEachIdentifier(c,b,a.proxy(function(a,b){this.setDisabledState(a,!1,b)},this)),this.render()},g.prototype.enableNode=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setDisabledState(a,!1,b)},this)),this.render()},g.prototype.toggleNodeDisabled=function(b,c){this.forEachIdentifier(b,c,a.proxy(function(a,b){this.setDisabledState(a,!a.state.disabled,b)},this)),this.render()},g.prototype.forEachIdentifier=function(b,c,d){c=a.extend({},f.options,c),b instanceof Array||(b=[b]),a.each(b,a.proxy(function(a,b){d(this.identifyNode(b),c)},this))},g.prototype.identifyNode=function(a){return"number"==typeof a?this.nodes[a]:a},g.prototype.search=function(b,c){c=a.extend({},f.searchOptions,c),this.clearSearch({render:!1});var d=[];if(b&&b.length>0){c.exactMatch&&(b="^"+b+"$");var e="g";c.ignoreCase&&(e+="i"),d=this.findNodes(b,e),a.each(d,function(a,b){b.searchResult=!0})}return c.revealResults?this.revealNode(d):this.render(),this.$element.trigger("searchComplete",a.extend(!0,{},d)),d},g.prototype.clearSearch=function(b){b=a.extend({},{render:!0},b);var c=a.each(this.findNodes("true","g","searchResult"),function(a,b){b.searchResult=!1});b.render&&this.render(),this.$element.trigger("searchCleared",a.extend(!0,{},c))},g.prototype.findNodes=function(b,c,d){c=c||"g",d=d||"text";var e=this;return a.grep(this.nodes,function(a){var f=e.getNodeValue(a,d);return"string"==typeof f?f.match(new RegExp(b,c)):void 0})},g.prototype.getNodeValue=function(a,b){var c=b.indexOf(".");if(c>0){var e=a[b.substring(0,c)],f=b.substring(c+1,b.length);return this.getNodeValue(e,f)}return a.hasOwnProperty(b)?a[b].toString():d};var h=function(a){b.console&&b.console.error(a)};a.fn[e]=function(b,c){var d;return this.each(function(){var f=a.data(this,e);"string"==typeof b?f?a.isFunction(f[b])&&"_"!==b.charAt(0)?(c instanceof Array||(c=[c]),d=f[b].apply(f,c)):h("No such method : "+b):h("Not initialized, can not call method : "+b):"boolean"==typeof b?d=f:a.data(this,e,new g(this,a.extend(!0,{},b)))}),d||this}}(jQuery,window,document);
|
@@ -0,0 +1,22 @@
|
|
1
|
+
$(document).ready(function() {
|
2
|
+
danta.init();
|
3
|
+
});
|
4
|
+
|
5
|
+
var danta = {
|
6
|
+
init: function() {
|
7
|
+
this.connectWebSocketClient();
|
8
|
+
this.initTree();
|
9
|
+
this.initPlayer();
|
10
|
+
},
|
11
|
+
connectWebSocketClient: function() {
|
12
|
+
webSocketClient.connect();
|
13
|
+
},
|
14
|
+
initTree: function() {
|
15
|
+
videoLibrary.get();
|
16
|
+
},
|
17
|
+
initPlayer: function() {
|
18
|
+
playerModal.init(
|
19
|
+
function() { videoTree.deselectAllNodes(); }
|
20
|
+
);
|
21
|
+
}
|
22
|
+
};
|