pig-media-server 0.3.2 → 2

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/bin/pig-media-server +4 -1
  4. data/gulpfile.js +33 -0
  5. data/javascripts/application.js +117 -0
  6. data/javascripts/chromecast.js +57 -0
  7. data/javascripts/components/head.js +106 -0
  8. data/javascripts/components/list.js +104 -0
  9. data/javascripts/components/new_flag.js +23 -0
  10. data/javascripts/components/player.js +171 -0
  11. data/javascripts/components/query_list.js +68 -0
  12. data/javascripts/components/sort.js +64 -0
  13. data/javascripts/components/watch.js +48 -0
  14. data/javascripts/controller.js +62 -0
  15. data/javascripts/custom_list.js +14 -0
  16. data/javascripts/event_dispatcher.js +21 -0
  17. data/javascripts/recent.js +34 -0
  18. data/javascripts/utils.js +22 -0
  19. data/javascripts/video.js +10 -0
  20. data/lib/pig-media-server/api.rb +96 -0
  21. data/lib/pig-media-server/aspect.rb +10 -5
  22. data/lib/pig-media-server/backup.rb +69 -0
  23. data/lib/pig-media-server/cli.rb +60 -25
  24. data/lib/pig-media-server/crawl.rb +41 -5
  25. data/lib/pig-media-server/kindle_send.rb +31 -24
  26. data/lib/pig-media-server/model/data.rb +106 -0
  27. data/lib/pig-media-server/model/migrate.rb +34 -0
  28. data/lib/pig-media-server/model/pig.rb +11 -2
  29. data/lib/pig-media-server/version.rb +1 -1
  30. data/lib/pig-media-server/views/_custom_links.haml +4 -0
  31. data/lib/pig-media-server/views/_ft_flv.haml +1 -0
  32. data/lib/pig-media-server/views/_ft_pdf.haml +0 -0
  33. data/lib/pig-media-server/views/_ft_video.haml +9 -4
  34. data/lib/pig-media-server/views/_link.haml +4 -1
  35. data/lib/pig-media-server/views/_new_flag.haml +1 -1
  36. data/lib/pig-media-server/views/app.scss +10 -1
  37. data/lib/pig-media-server/views/bundle.js +13 -0
  38. data/lib/pig-media-server/views/chromecast.coffee +54 -0
  39. data/lib/pig-media-server/views/config.coffee +13 -1
  40. data/lib/pig-media-server/views/config.haml +27 -4
  41. data/lib/pig-media-server/views/feed.builder +3 -2
  42. data/lib/pig-media-server/views/flv.coffee +33 -0
  43. data/lib/pig-media-server/views/index.haml +11 -5
  44. data/lib/pig-media-server/views/meta.haml +4 -4
  45. data/lib/pig-media-server/views/movie.coffee +65 -39
  46. data/lib/pig-media-server/views/react.haml +22 -0
  47. data/lib/pig-media-server/views/remote.haml +2 -2
  48. data/lib/pig-media-server/views/session.coffee +5 -0
  49. data/lib/pig-media-server/views/storage.coffee +5 -16
  50. data/lib/pig-media-server/views/sub.haml +5 -6
  51. data/lib/pig-media-server/views/subview.coffee +109 -19
  52. data/lib/pig-media-server/views/tv.coffee +97 -0
  53. data/lib/pig-media-server/views/tv.haml +33 -0
  54. data/lib/pig-media-server/views/unread.coffee +10 -0
  55. data/lib/pig-media-server/web.rb +102 -37
  56. data/package.json +23 -0
  57. data/pig-media-server.gemspec +5 -0
  58. metadata +123 -38
@@ -0,0 +1,68 @@
1
+ class Item extends React.Component {
2
+ url(){ return `/?query=${encodeURIComponent(this.props.query)}` }
3
+
4
+ click(){
5
+ this.props.state.open(this.url());
6
+ }
7
+
8
+ delete_query(){
9
+ if(confirm('Really?')){
10
+ $.post("/api/r/delete_query_list", {query: this.props.query}).done((data)=>{
11
+ this.props.update_list();
12
+ });
13
+ }
14
+ }
15
+ render(){
16
+ return <span className='main_span'>
17
+ <a href='javascript:void(0)' onClick={()=> this.click()}>
18
+ {this.props.query}
19
+ </a>
20
+ <a href='javascript:void(0)' className='delete' onClick={()=> this.delete_query()}>
21
+ Delete
22
+ </a>
23
+ </span>
24
+ }
25
+ }
26
+
27
+ class QueryList extends React.Component {
28
+ constructor(props){
29
+ super(props);
30
+ this.state = {};
31
+ this.state.list = [];
32
+ this.controller = new Controller()
33
+ }
34
+
35
+ update_list(){
36
+ $.get("/api/r/query_list").done((data)=>{
37
+ this.state.list = data;
38
+ this.setState(this.state);
39
+ });
40
+ }
41
+
42
+ componentDidMount(){
43
+ this.update_list();
44
+ }
45
+
46
+ show(){
47
+ if(location.pathname == '/'){
48
+ if(!this.controller.query()){
49
+ return true;
50
+ } else {
51
+ return false;
52
+ }
53
+ } else {
54
+ return false
55
+ }
56
+ }
57
+
58
+ render(){
59
+ var items = $.map(this.state.list, (query)=>{
60
+ return <Item key={query} query={query} state={this.props.state} update_list={()=> this.update_list()}/>
61
+ });
62
+ return <div>
63
+ {this.show() ? items : null}
64
+ </div>
65
+ }
66
+ }
67
+
68
+ window.QueryList = QueryList;
@@ -0,0 +1,64 @@
1
+ class QuerySave extends React.Component{
2
+ constructor(props){
3
+ super(props);
4
+ this.controller = new Controller();
5
+ }
6
+
7
+ click(){
8
+ var query = decodeURIComponent(this.controller.query());
9
+ $.post("/api/r/query_list", {query: query})
10
+ }
11
+ render(){
12
+ return <span>
13
+ <a href='javascript:void(0)' onClick={()=> this.click()}>Save Query</a>
14
+ </span>
15
+ }
16
+ }
17
+
18
+ class Sort extends React.Component{
19
+ constructor(props){
20
+ super(props);
21
+ this.controller = new Controller();
22
+ }
23
+
24
+ sort_by_date(){
25
+ var query = this.controller.query();
26
+ var new_url = `/?query=${query}&sort=date&order=descending`
27
+ history.pushState("", "", new_url);
28
+ this.props.state.initialize();
29
+ }
30
+
31
+ sort_by_name(){
32
+ var query = this.controller.query();
33
+ var new_url = `/?query=${query}&sort=name&order=ascending`
34
+ history.pushState("", "", new_url);
35
+ this.props.state.initialize();
36
+ }
37
+
38
+ change_order(order){
39
+ var query = this.controller.query();
40
+ var sort = this.controller.params().sort;
41
+ var new_url = `/?query=${query}&sort=${sort}&order=${order}`
42
+ history.pushState("", "", new_url);
43
+ this.props.state.initialize();
44
+
45
+ }
46
+
47
+ can_change_order(){ return !!this.controller.params().sort; }
48
+ render(){
49
+ return <p>
50
+ <a href="javascript:void(0)" onClick={()=> this.sort_by_date()}>Sort By Date</a>
51
+ <a href="javascript:void(0)" onClick={()=> this.sort_by_name()}>Sort By Name</a>
52
+ {this.can_change_order() ?
53
+ <span>
54
+ <a href="javascript:void(0)" onClick={()=> this.change_order('ascending')}>Ascending</a>
55
+ <a href="javascript:void(0)" onClick={()=> this.change_order('descending')}>Descending</a>
56
+ </span>
57
+ : null
58
+ }
59
+ <QuerySave />
60
+ </p>
61
+ }
62
+ }
63
+
64
+ window.Sort = Sort;
@@ -0,0 +1,48 @@
1
+ class ChromeCast extends React.Component {
2
+ is_video(){ var e = ext(this.props.item.name); return e == 'mp4' || e == 'flv'; }
3
+
4
+ click(){ window.chrome_cast(this.props.item.url, this.props.item.key) }
5
+ render(){
6
+ return <span>
7
+ {this.is_video() ?
8
+ <span>
9
+ <a
10
+ className="watch"
11
+ href="javascript:void(0)"
12
+ title={this.props.item.name}
13
+ onClick={()=> this.click()}
14
+ >ChromeCast</a>
15
+ &nbsp;
16
+ </span>
17
+ : null}
18
+ </span>
19
+ }
20
+ }
21
+
22
+
23
+ class Watch extends React.Component {
24
+ is_video(){
25
+ var e = ext(this.props.item.name);
26
+ return e == 'mp4' || e == 'flv';
27
+ }
28
+
29
+ set_video(){ this.props.state.models.video.set(this.props.item); }
30
+ render(){
31
+ return <span>
32
+ {this.is_video() ?
33
+ <span>
34
+ <a
35
+ className="watch"
36
+ href="javascript:void(0)"
37
+ title={this.props.item.name}
38
+ onClick={()=> this.set_video()}
39
+ >Watch</a>
40
+ &nbsp;
41
+ </span>
42
+ : null}
43
+ </span>
44
+ }
45
+ }
46
+
47
+ window.Watch = Watch;
48
+ window.ChromeCast = ChromeCast;
@@ -0,0 +1,62 @@
1
+ class Controller {
2
+ route(){
3
+ var query =this.params().query;
4
+ var result = {}
5
+ switch(location.pathname){
6
+ case "/":
7
+ result.page = "list";
8
+ if(!!query){
9
+ result.api_url = `/api/r/search?query=${query}`
10
+ if(!!this.params().sort){ result.api_url += `&sort=${this.params().sort}` }
11
+ if(!!this.params().order){ result.api_url += `&order=${this.params().order}` }
12
+ if(!!this.params().page){ result.api_url += `&page=${this.params().page}` }
13
+ $('title').text(decodeURIComponent(this.query()));
14
+ } else {
15
+ result.api_url = null;
16
+ }
17
+ break;
18
+
19
+ case "/latest":
20
+ result.page = "list";
21
+ result.api_url = '/api/r/latest';
22
+ $('title').text("Latest - Pig Media Server");
23
+ break;
24
+ case "/custom":
25
+ result.page = "list";
26
+ result.api_url = `/api/r/custom?name=${this.params().name}`;
27
+ $('title').text(decodeURIComponent(this.params().name));
28
+ break;
29
+
30
+ case "/recommend":
31
+ result.page = "list";
32
+ result.api_url = `/api/r/recommend?name=${this.params().name}`;
33
+ $('title').text('Recommend');
34
+ break;
35
+ }
36
+ return result;
37
+ }
38
+
39
+
40
+
41
+ params(){
42
+ var arg = new Object;
43
+ var pair = location.search.substring(1).split('&');
44
+ for(var i=0; pair[i]; i++) {
45
+ var kv = pair[i].split('=');
46
+ arg[kv[0]] = kv[1];
47
+ }
48
+ return arg;
49
+ }
50
+
51
+ query(){ return this.params().query; }
52
+
53
+ can_sort_and_paging(){
54
+ if(location.pathname == '/'){
55
+ return !!this.query();
56
+ } else {
57
+ return false;
58
+ }
59
+ }
60
+ }
61
+
62
+ window.Controller = Controller;
@@ -0,0 +1,14 @@
1
+ class CustomList {
2
+ constructor(app){
3
+ this.app = app;
4
+ this.list = []
5
+ }
6
+ load(){
7
+ $.get('/api/r/custom_list').done((data)=>{
8
+ this.list = data;
9
+ this.app.update_state();
10
+ });
11
+ }
12
+ }
13
+
14
+ window.CustomList = CustomList;
@@ -0,0 +1,21 @@
1
+ class EventDispatcher {
2
+ constructor(){
3
+ this.listeners = {};
4
+ }
5
+
6
+ addEventListener(type, callback){
7
+ if (!this.listeners[type]) { this.listeners[type] = []; }
8
+ this.listeners[type].push(callback);
9
+ }
10
+ clearEventListener(){ this.listeners = {}; }
11
+
12
+ dispatchEvent(event) {
13
+ if (this.listeners[event.type]) {
14
+ for (var listener in this.listeners[event.type]) {
15
+ this.listeners[event.type][listener].apply(this.listeners, arguments);
16
+ }
17
+ }
18
+ }
19
+ }
20
+
21
+ window.EventDispatcher = EventDispatcher;
@@ -0,0 +1,34 @@
1
+ class Recent {
2
+ constructor(app){
3
+ this.app = app;
4
+ }
5
+
6
+ login(){ return !!this.app.state.session.user_id }
7
+
8
+ load(){
9
+ if(this.login()){
10
+ var dd = new Date();
11
+ $.get('/recents', {stamp: dd.getTime()}).done((data)=>{
12
+ this.app.state.recents = data;
13
+ this.app.update_state();
14
+ });
15
+ } else {
16
+ }
17
+ }
18
+
19
+ use(key){
20
+ if(this.login()){
21
+ var dd = new Date();
22
+ $.get('/recents', {stamp: dd.getTime()}).done((recents)=>{
23
+ recents[key] = {time: parseInt((new Date)/1000), type: 'movie'}
24
+ $.post("/recents", {data: JSON.stringify(recents)});
25
+ this.app.state.recents = recents;
26
+ this.app.update_state();
27
+ });
28
+ } else {
29
+ console.log("kotti");
30
+ }
31
+ }
32
+ }
33
+
34
+ window.Recent = Recent;
@@ -0,0 +1,22 @@
1
+ window.round = (i)=>{
2
+ i = i*10;
3
+ return Math.round(i)/10
4
+ }
5
+
6
+ window.size_pretty = (size)=>{
7
+ var size = parseFloat(String(size));
8
+ var result = size;
9
+ if(size < 1024){
10
+ result = `${size} Bytes`
11
+ } else if(size < 1024*1024){
12
+ result = `${round(size / 1024)} KB`
13
+ } else if(size < 1024*1024*1024){
14
+ result = `${round(size / (1024*1024))} MB`
15
+ } else if(size < 1024*1024*1024*1024){
16
+ result = `${round(size / (1024*1024*1024))} GB`
17
+ }
18
+ return result
19
+ }
20
+
21
+
22
+ window.ext = (str)=>{ return String(str).split('.').pop().toLowerCase(); }
@@ -0,0 +1,10 @@
1
+ class Video extends EventDispatcher{
2
+ set(item){
3
+ this.item = null;
4
+ this.dispatchEvent({type: 'videoUpdated'});
5
+ this.item = item;
6
+ this.dispatchEvent({type: 'videoUpdated'});
7
+ }
8
+ }
9
+
10
+ window.Video = Video;
@@ -0,0 +1,96 @@
1
+ require 'active_support/concern'
2
+ module PigMediaServer
3
+ module API
4
+ extend ActiveSupport::Concern
5
+ def page
6
+ params[:page].to_i < 1 ? 1 : params[:page].to_i
7
+ end
8
+
9
+ def size
10
+ params[:size] ? params[:size].to_i : 50
11
+ end
12
+
13
+ def list_to_json list
14
+ list.map{|x|
15
+ hash = x.to_hash
16
+ hash['custom_links'] = partial :_custom_links, locals: {record: x}
17
+ hash['metadata'] = !!x.metadata and x.metadata != ''
18
+ hash['srt'] = !!x.metadata and x.metadata != ''
19
+ hash
20
+ }.to_json
21
+ end
22
+
23
+ included do
24
+ get '/api/r/latest' do
25
+ content_type :json
26
+ list_to_json(Groonga['Files'].select.paginate([key: 'mtime', order: 'descending'], size: size, page: page).map{|x| Pig.new(x)})
27
+ end
28
+
29
+ get '/api/r/custom' do
30
+ content_type :json
31
+ c = config['custom_list'][params[:name]]
32
+ list_to_json(Pig.find JSON.parse(open(c).read))
33
+ end
34
+
35
+ get '/api/r/recommend' do
36
+ content_type :json
37
+ list = []
38
+ begin
39
+ keys = open("#{config['user_data_path']}/recommend/#{params[:name]}").read.split("\n")
40
+ list = Pig.find(keys)
41
+ rescue
42
+ end
43
+ list_to_json(list)
44
+ end
45
+
46
+ get '/api/r/search' do
47
+ content_type :json
48
+ list_to_json(Pig.search params.merge(page: page))
49
+ end
50
+
51
+ get '/api/r/config' do
52
+ content_type :json
53
+ config.to_json
54
+ end
55
+
56
+ get '/api/r/session' do
57
+ content_type :json
58
+ session.to_hash.to_json
59
+ end
60
+
61
+ get '/api/r/custom_list' do
62
+ content_type :json
63
+ if config['custom_list']
64
+ config['custom_list'].to_json
65
+ else
66
+ {}.to_json
67
+ end
68
+ end
69
+
70
+ get '/api/r/query_list' do
71
+ content_type :json
72
+ Groonga['QueryList'].select.map{|x| x.query }.sort.to_json
73
+ end
74
+
75
+ post '/api/r/query_list' do
76
+ content_type :json
77
+ key = Digest::MD5.hexdigest(params[:query])
78
+ unless Groonga['QueryList'][key]
79
+ Groonga['QueryList'].add(key)
80
+ Groonga['QueryList'][key].query = params[:query]
81
+ end
82
+ {result: true}.to_json
83
+ end
84
+
85
+ post '/api/r/delete_query_list' do
86
+ content_type :json
87
+ key = Digest::MD5.hexdigest(params[:query])
88
+ if Groonga['QueryList'][key]
89
+ Groonga['QueryList'].delete key
90
+ end
91
+ {result: true}.to_json
92
+
93
+ end
94
+ end
95
+ end
96
+ end
@@ -7,22 +7,27 @@ module PigMediaServer
7
7
  pit_config = Pit.get 'Pig Media Server'
8
8
  while true
9
9
  GC.start
10
- begin
10
+ #begin
11
11
  q = open("#{pit_config['user_data_path']}/rate/queue.txt").read.split("\n")
12
12
  q.each do |x|
13
- next if x == ''
13
+ #begin
14
+ #next if x == ''
14
15
  key = x.split(' ').first
15
16
  rate = x.split(' ').last
16
17
  pig = Pig.find key
18
+ next unless pig
19
+ puts pig.path
17
20
  if rate == '16:9'
18
21
  system 'MP4Box', '-add', "#{pig.record.path}:par=1:1", '-new', "#{pig.record.path}.MP4"
19
22
  FileUtils.mv "#{pig.record.path}.MP4", pig.record.path
20
23
  end
24
+ #rescue
25
+ #end
21
26
  end
22
27
  open("#{pit_config['user_data_path']}/rate/queue.txt", 'w'){|x| x.puts ''}
23
- rescue => e
24
- p e
25
- end
28
+ #rescue => e
29
+ # p e
30
+ #end
26
31
  sleep 5
27
32
  end
28
33
  end
@@ -0,0 +1,69 @@
1
+ require 'pig-media-server/script'
2
+ require 'tmpdir'
3
+
4
+ module PigMediaServer
5
+ class Backup
6
+ def backup
7
+ pit_config = Pit.get 'Pig Media Server'
8
+ backup_path = pit_config['backup_path']
9
+ Dir.mktmpdir do |tmpdir|
10
+ FileUtils.cd tmpdir
11
+ date = Date.today
12
+
13
+ a = $f.select.to_a
14
+ open("backup.json", "w"){|f|
15
+ a.each_with_index{|x,i|
16
+ f.puts [x._key, x.path, x.metadata, x.srt].to_json
17
+ puts "#{i+1} / #{a.count}" if i%100 ==0
18
+ }
19
+ }
20
+ open('groonga.schema', 'w'){|x| x.puts Groonga::Schema.dump}
21
+ system "tar zcvf #{date}.tar.gz backup.json groonga.schema"
22
+ FileUtils.mv "#{date}.tar.gz", backup_path
23
+ end
24
+ end
25
+
26
+ def restore_from path
27
+ raise unless File.exist? path
28
+ pit_config = Pit.get 'Pig Media Server'
29
+ Dir.glob("#{pit_config['groonga']}/**/*").each{|x| FileUtils.rm x}
30
+ Groonga::Database.create path: pit_config['groonga']+"/search"
31
+ Dir.mktmpdir do |tmpdir|
32
+ FileUtils.cd tmpdir
33
+ FileUtils.cp path, "."
34
+ system 'tar', 'xvf', Dir.glob("*.gz").first
35
+ system 'ls'
36
+ FileUtils.rm Dir.glob("*.gz").first
37
+ Groonga::Schema.restore(open('groonga.schema').read){|schema| schema.define }
38
+ $f = Groonga['Files']
39
+ json =open("backup.json").read.split("\n")
40
+ json.each_with_index{|x,i|
41
+ x = JSON.parse x
42
+ $f.add(x[0])
43
+ $f[x[0]].path = x[1]
44
+ $f[x[0]].metadata = x[2]
45
+ $f[x[0]].srt = x[3]
46
+ puts "#{i+1} / #{json.count}" if i%100 == 0 or i+1 == json.count
47
+ }
48
+ end
49
+ ary = $f.select.to_a
50
+
51
+ lost = []
52
+
53
+ ary.each_with_index{|x,i|
54
+ if x.path.nil?
55
+ $f.delete x._key
56
+ next
57
+ end
58
+ unless File.exist? x.path
59
+ puts x.path
60
+ $f.delete x._key
61
+ next
62
+ end
63
+ x.mtime = File::Stat.new(x.path).mtime.to_i
64
+ puts "#{i+1} / #{ary.count}" if (i+1)%1000 == 0 or i+1 == ary.count
65
+ }
66
+ lost.sort.each{|x| puts x}
67
+ end
68
+ end
69
+ end
@@ -1,27 +1,62 @@
1
- case ARGV[0]
2
- when 'setup'
3
- require 'fileutils'
4
- config = Pit.get("Pig Media Server", require:{
5
- 'path' => 'Path of your storage',
6
- 'groonga' => "Path of groonga's files",
7
- 'exclude_path' => 'Exclude Path(Array)',
8
- 'user_data_path' => 'Path of User Data'
9
- })
1
+ require 'thor'
10
2
 
11
- puts "Path: #{config['path']}"
12
- puts "Groonga: #{config['groonga']}"
13
- FileUtils.mkdir_p config['user_data_path']
14
- when 'crawl'
15
- require 'pig-media-server/crawl'
16
- PigMediaServer::Crawl.new.all
17
- when 'server'
18
- port = ARGV[1] ? ARGV[1].to_i : 8080
19
- require 'pig-media-server/web'
20
- PigMediaServer::Web.run! host: '0.0.0.0', port: port
21
- when 'aspect'
22
- require 'pig-media-server/aspect'
23
- PigMediaServer::Aspect.new.run
24
- when 'kindle-send'
25
- require 'pig-media-server/kindle_send'
26
- PigMediaServer::KindleSend.new.run
3
+ module PigMediaServer
4
+ class CLI < Thor
5
+ desc 'setup', 'setup configurations'
6
+ def setup
7
+ require 'fileutils'
8
+ config = Pit.get("Pig Media Server", require:{
9
+ 'hostname' => 'Your host name',
10
+ 'path' => 'Path of your storage',
11
+ 'groonga' => "Path of groonga's files",
12
+ 'exclude_path' => 'Exclude Path(Array)',
13
+ 'user_data_path' => 'Path of User Data'
14
+ })
15
+
16
+ puts "Path: #{config['path']}"
17
+ puts "Groonga: #{config['groonga']}"
18
+ FileUtils.mkdir_p config['user_data_path']
19
+ end
20
+
21
+ desc 'crawl', 'run crawler'
22
+ def crawl
23
+ require 'pig-media-server/crawl'
24
+ PigMediaServer::Crawl.new.all
25
+ end
26
+
27
+ desc 'server [PORT]', 'run server'
28
+ option :bind, :type => :string, :default => '0.0.0.0'
29
+ option :port, :type => :numeric, :default => 8080
30
+ def server(port = nil)
31
+ require 'pig-media-server/web'
32
+ port ||= options[:port]
33
+ Sinatra::Base.server.delete 'HTTP' # conflict with HTTP.gem
34
+ PigMediaServer::Web.run! :bind => options[:bind], :port => port.to_i
35
+ end
36
+
37
+ desc 'aspect', 'fix aspect'
38
+ def aspect
39
+ require 'pig-media-server/aspect'
40
+ PigMediaServer::Aspect.new.run
41
+ end
42
+
43
+ desc 'kindle-send', 'send to kindle'
44
+ def kindle_send
45
+ require 'pig-media-server/kindle_send'
46
+ PigMediaServer::KindleSend.new.run
47
+ end
48
+
49
+ desc 'backup', 'backup groonga\'s data'
50
+ def backup
51
+ require 'pig-media-server/backup'
52
+ PigMediaServer::Backup.new.backup
53
+ end
54
+
55
+ option :path, required: true
56
+ desc 'restore', 'restore groonga\'s data'
57
+ def restore
58
+ require 'pig-media-server/backup'
59
+ PigMediaServer::Backup.new.restore_from options[:path]
60
+ end
61
+ end
27
62
  end