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
@@ -4,28 +4,109 @@ mode = 'eroge'
4
4
  current = null
5
5
 
6
6
  eroge_next = ->
7
- if current == null or current == undefined
8
- current = ps[0]
7
+ unless $('video').get(0)
8
+ if current == null or current == undefined
9
+ current = ps[0]
10
+ else
11
+ current = ps[ids.indexOf($(current).attr('id'))+1]
12
+
13
+ before = ps[ids.indexOf($(current).attr('id'))-1]
14
+ if $(before).find('img').length == 0
15
+ $(before).css display: 'none'
16
+ if $(current).find('img').length != 0
17
+ $('html, body').animate {scrollTop: $(current).offset().top}, 'fast'
18
+ current = ps[ids.indexOf($(current).attr('id'))+1]
9
19
  else
10
- current = ps[ids.indexOf($(current).attr('id'))+1]
11
-
12
- before = ps[ids.indexOf($(current).attr('id'))-1]
13
- if $(before).find('img').length == 0
14
- $(before).css display: 'none'
15
- if $(current).find('img').length != 0
16
- $('html, body').animate {scrollTop: $(current).offset().top}, 'fast'
17
- current = ps[ids.indexOf($(current).attr('id'))+1]
20
+ seek(15)
21
+
18
22
 
19
23
  eroge_prev = ->
20
- if current == null or current ==undefined
21
- current = ps[0]
24
+ unless $('video').get(0)
25
+ if current == null or current ==undefined
26
+ current = ps[0]
27
+ else
28
+ current = ps[ids.indexOf($(current).attr('id'))-1]
29
+ if $(current).find('img').length != 0
30
+ $('html, body').animate {scrollTop: $(current).offset().top}, 'fast'
31
+ $(current).css display: 'block'
22
32
  else
23
- current = ps[ids.indexOf($(current).attr('id'))-1]
24
- if $(current).find('img').length != 0
25
- $('html, body').animate {scrollTop: $(current).offset().top}, 'fast'
26
- $(current).css display: 'block'
33
+ seek(-15)
34
+
35
+ seek = (count)->
36
+ node = document.querySelector 'video'
37
+ node.currentTime = node.currentTime + count
38
+ window.gyazo = ->
39
+ c = document.querySelector '#canvas'
40
+ v = document.querySelector 'video'
41
+ context = c.getContext '2d'
42
+ c.width = v.videoWidth
43
+ c.height = v.videoHeight
44
+ context.drawImage(v, 0, 0)
45
+ url = c.toDataURL()
46
+ $.post('/gyazo', {url: url, point: localStorage.gyazo}).success((data)->
47
+ window.open(data.url, "", "width=500,height=400")
48
+ )
49
+
50
+ window.tweet = ->
51
+ c = document.querySelector '#canvas'
52
+ v = document.querySelector 'video'
53
+ context = c.getContext '2d'
54
+ c.width = v.videoWidth
55
+ c.height = v.videoHeight
56
+ context.drawImage(v, 0, 0)
57
+ url = c.toDataURL()
58
+ $.post('/gyazo/tweet', {url: url}).success((data)->
59
+ true
60
+ )
61
+
62
+ window.tweet_with_comment = ->
63
+ c = document.querySelector '#canvas'
64
+ v = document.querySelector 'video'
65
+ context = c.getContext '2d'
66
+ c.width = v.videoWidth
67
+ c.height = v.videoHeight
68
+ context.drawImage(v, 0, 0)
69
+ url = c.toDataURL()
70
+ comment = prompt 'Tweet'
71
+ $.post('/gyazo/tweet', {url: url, comment: comment}).success((data)->
72
+ true
73
+ )
27
74
 
28
75
 
76
+ video_play = (node)->
77
+ video = $('#url').text()
78
+ $node = $(node)
79
+ console.log "play #{video} #{$node.attr('time')} #{$node.attr('master_id')}"
80
+ $video = $('<video>').attr(
81
+ src: video
82
+ master_id: $node.attr('master_id'),
83
+ image: $node.attr('src'),
84
+ controls: 'controls'
85
+ time: $node.attr('time')
86
+ ).css('max-width': '100%', 'max-height': '100%')
87
+ $("#p_#{$node.attr('master_id')}").html($video)
88
+ $video = $("#p_#{$node.attr('master_id')} video")
89
+ $video.bind('canplay', (e)->
90
+ console.log e
91
+ e.target.currentTime = parseFloat($(e.target).attr('time'))-5
92
+ $(e.target).unbind('canplay')
93
+ e.target.play()
94
+ $('html,body').animate(scrollTop: $(e.target).offset().top)
95
+ )
96
+ $video.get(0).load()
97
+ $video.click(->
98
+ $v = $(this)
99
+ master_id = $v.attr('master_id')
100
+ $("#p_#{master_id}").html(
101
+ $('<img>').attr(
102
+ src: $v.attr('image'),
103
+ class: 'srt_image',
104
+ id: "image_#{master_id}",
105
+ time: $v.attr('time'),
106
+ master_id: master_id
107
+ )
108
+ )
109
+ )
29
110
  window.sub_view = ->
30
111
  for n in $('.srt_line')
31
112
  a = $(n).html().split('<br>')
@@ -34,7 +115,10 @@ window.sub_view = ->
34
115
  $.get('/api/get', name: "sub/caps/#{$('#key').text()}").success (data)->
35
116
  caps = JSON.parse(data)
36
117
  $.each caps, (i,n)->
37
- $("##{i}").before $('<p>').append($('<img>').attr(src: n)).attr(class: 'srt_image', id: "image_#{i}")
118
+ time = parseFloat(i.split('_')[1])/1000
119
+ $("##{i}").before $('<p>').append(
120
+ $('<img>').attr(src: n).attr(class: 'srt_image', id: "image_#{i}", time: time, master_id: i)
121
+ ).attr(id: "p_#{i}")
38
122
  ps = document.querySelectorAll('.srt p')
39
123
  $('h3').after(
40
124
  $('<button>').text('Reset Capture').click ->
@@ -51,7 +135,13 @@ window.sub_view = ->
51
135
  eroge_next()
52
136
  when 75
53
137
  eroge_prev()
138
+ when 71
139
+ gyazo() if document.querySelector('video')
140
+ when 84
141
+ tweet() if document.querySelector('video')
142
+ when 67
143
+ tweet_with_comment() if document.querySelector('video')
144
+
54
145
  $ ->
55
- $(document).on('click', '.srt_image', -> eroge_next()).css('cursor','pointer')
146
+ $(document).on('click', '.srt_image', -> video_play(this)).css('cursor','pointer')
56
147
  #$(document).on('touchend', '.srt_image', -> eroge_next())
57
-
@@ -0,0 +1,97 @@
1
+ TV = ->
2
+ @data = []
3
+ @list = []
4
+ @initial = true
5
+ @get = =>
6
+ $.getJSON('/tv/list').done((data)=>
7
+ @data = data
8
+ @bind()
9
+ @render()
10
+ ).fail((a,b,c)=>
11
+ @bind()
12
+ )
13
+
14
+ @save = =>
15
+ $.post('/tv/list', data: JSON.stringify(@data)).success(=> @render())
16
+
17
+ @cast = =>
18
+ @initial = false
19
+ @list = []
20
+ $.ajaxSetup({ async: false })
21
+ for d in @data
22
+ $.get("/feed", query: d).success((res)=>
23
+ for item in $(res).find('item')
24
+ title = $(item).find('title').text()
25
+ link = $(item).find('link').text()
26
+ date = Date.parse $(item).find('pubDate').text()
27
+ key = $(item).find('key').text()
28
+ @list.push [title, link, date, key]
29
+ )
30
+ @list = @list.sort((a,b)->
31
+ a[2] > b[2]
32
+ )
33
+ for l in @list
34
+ @create_link(l)
35
+ $.each $('a.watch'), -> watch(this)
36
+ set_new()
37
+
38
+ for n in $('.main_span')
39
+ $(n).remove() if n.dataset.new == undefined
40
+
41
+ $('a.watch').first().click()
42
+ @create_link = (ary)=>
43
+ $span = $('<span>')
44
+ $span.addClass('main_span')
45
+ $span.attr(id: ary[3])
46
+
47
+ $new_flag = $('<span>').addClass('new_flag')
48
+ $new_flag.attr(key: "movie/#{ary[3]}", style: 'color:lime; font-size:large')
49
+
50
+ $a = $('<a>')
51
+ $a.addClass('main_link').text(ary[0]).attr(href: ary[1], key: ary[3])
52
+
53
+ $watch = $('<a>')
54
+ $watch.addClass('watch').text(' Watch').attr(href: 'javascript:void(0)', url: ary[1], key: ary[3], title: ary[0])
55
+
56
+ $span.append($new_flag)
57
+ $span.append($a)
58
+ $span.append($watch)
59
+ $('#list').append($span)
60
+
61
+
62
+
63
+ @bind = =>
64
+ $('#start').click => @cast()
65
+ $('button').click =>
66
+ t = $('input#title').val()
67
+ unless t == ''
68
+ @data.push t
69
+ @save()
70
+
71
+ @delete = ($node)=>
72
+ d = $node.attr('data')
73
+ @data.splice @data.indexOf(d), 1
74
+ @save()
75
+
76
+ $node.parent().remove()
77
+
78
+
79
+ @render = =>
80
+ $('ul').html('')
81
+ for d in @data
82
+ $li = $('<li>').text(d+" ")
83
+ $li.append(
84
+ $('<a>').text('削除').attr(href: 'javascript:void(0)', data: d).click((e)=>
85
+ @delete($(e.target))
86
+ )
87
+ )
88
+ $('ul').append $li
89
+ @cast() if @initial
90
+
91
+ @start = =>
92
+ @get()
93
+ @start()
94
+
95
+ $ ->
96
+ if $('#tv').text() == 'true'
97
+ t = new TV()
@@ -0,0 +1,33 @@
1
+ !!!
2
+ %title= title
3
+ %meta(content='width=320, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' name='viewport')
4
+ %script{src: 'https://code.jquery.com/jquery.min.js'}
5
+ -%w{flv storage session movie unread book book2 swipe tv}.each do |js|
6
+ %script{src: "/#{js}.js"}
7
+ %link{href: '/app.css', rel: 'stylesheet', type: 'text/css'}
8
+ :css
9
+ .none{display:none}
10
+ #area=''
11
+ #all
12
+ -unless session[:user_id]
13
+ %a{href: '/sessions'} Login
14
+ -else
15
+ Login as
16
+ %span#user_id=session[:user_id]
17
+ %a{href: 'javascript:void(0)', onclick: 'logout()'} Logout
18
+ %p=flash[:notice]
19
+ %h1
20
+ %a{href: '/'} #{config['page_title']}
21
+ %h2
22
+ %a#start{href: 'javascript:void(0)'} Cast 開始
23
+ %h3 お気に入りの番組(クエリ)を登録してください
24
+ %input#title
25
+ %button 追加
26
+ %ul
27
+ %li=''
28
+ %h3 再生リスト
29
+ %p#list=''
30
+ .none
31
+ %span#action=@action
32
+ %span#tv=true
33
+ %canvas#canvas
@@ -6,6 +6,16 @@ window.set_new = ->
6
6
  unless recents[key]
7
7
  $(this).text 'New!'
8
8
  $(this).parent().attr('data-new': true)
9
+ $(this).click ->
10
+ $node = $(this)
11
+ window.get_recents (recents)->
12
+ recents[$node.attr('key')] = {time: 0, type: 'movie'}
13
+ window.save_recents(recents)
14
+ setTimeout ->
15
+ $('.new_flag').text('')
16
+ $('.main_span').attr('data-new': '')
17
+ window.set_new()
18
+ , 1000
9
19
  count += 1
10
20
  if count == 0
11
21
  $('.main_link').css('margin-left', '0')
@@ -1,4 +1,5 @@
1
1
  require 'pig-media-server'
2
+ require 'pig-media-server/api'
2
3
  require 'pig-media-server/model/pig'
3
4
  require 'pig-media-server/model/comic'
4
5
  require 'sinatra/base'
@@ -12,21 +13,39 @@ require 'coffee_script'
12
13
  require 'rack/csrf'
13
14
  require 'redcarpet'
14
15
  require 'json'
16
+ require 'twitter'
17
+ require 'tempfile'
15
18
 
16
19
  module PigMediaServer
17
20
  CONFIG = Pit.get 'Pig Media Sever'
18
21
  class UserData
19
- def self.save json, user_id, path
20
- open("#{path}/#{user_id}.json", "w"){|f| f.puts json}
21
- true
22
+ def self.save user_id, key, value
23
+ AppData.set("user_data/#{user_id}/#{key}", value)
22
24
  end
23
25
 
24
- def self.load user_id, path
25
- return JSON.parse(open("#{path}/#{user_id}.json").read) rescue return {}
26
+ def self.load user_id, key
27
+ AppData.find("user_data/#{user_id}/#{key}")
26
28
  end
27
29
  end
28
30
 
29
31
  class Gyazo
32
+ def self.tweet url, comment, key, secret, token, token_secret, c
33
+ $config = $config ||Pit.get("Pig Media Server")
34
+ name = $config['gyazo_path'] + "/#{rand(256**16).to_s(16)}.png"
35
+ jpg = name.sub(/png$/, 'jpg')
36
+ img = url.sub(/data:image\/png;base64,/, '').unpack('m').first
37
+ open(name, 'w'){|f| f.puts img}
38
+ system "gm", "convert", name, jpg
39
+ client = Twitter::REST::Client.new do |config|
40
+ config.consumer_key = key
41
+ config.consumer_secret = secret
42
+ config.access_token = token
43
+ config.access_token_secret = token_secret
44
+ end
45
+ client.update_with_media(comment.to_s, open(jpg))# rescue nil
46
+ FileUtils.rm name
47
+ FileUtils.rm jpg
48
+ end
30
49
  def self.post url, point
31
50
  imagedata = url.sub(/data:image\/png;base64,/, '').unpack('m').first
32
51
  boundary = '----BOUNDARYBOUNDARY----'
@@ -60,22 +79,17 @@ EOF
60
79
 
61
80
  class Web < Sinatra::Base
62
81
  register Sinatra::Flash
82
+ include PigMediaServer::API
63
83
 
64
84
  configure do
65
- set :sessions, true
66
85
  set :haml, escape_html: true
67
86
  set :haml, attr_wrapper: '"'
68
- use Rack::Session::Cookie, expire_after: 60*60*24*28, secret: $session_secret || rand(256**16).to_s(16)
87
+ set :logging, true
88
+ use Rack::Session::Cookie, key: 'pigmeidaserver', secret: $session_secret || rand(256**16).to_s(16)
69
89
  end
70
90
 
71
91
  get '/' do
72
- if params[:query]
73
- redirect '/latest' if params[:query].empty?
74
- @page = params[:page].to_i < 1 ? 1 : params[:page].to_i
75
- @action = 'list'
76
- @list = Pig.search params.merge(page: @page)
77
- end
78
- haml :index
92
+ haml :react
79
93
  end
80
94
 
81
95
  get '/feed' do
@@ -85,23 +99,21 @@ EOF
85
99
  end
86
100
 
87
101
  get '/custom' do
88
- c = config['custom_list'][params[:name]]
89
- @page = params[:page].to_i < 1 ? 1 : params[:page].to_i
90
- @action = 'list'
91
- @list = Pig.find JSON.parse(open(c).read)
92
- @no_paging = true
93
- haml :index
102
+ haml :react
94
103
  end
95
104
 
96
105
  get '/latest' do
97
- @page = params[:page].to_i < 1 ? 1 : params[:page].to_i
98
- size = params[:size] ? params[:size].to_i : 50
99
- @list = Groonga['Files'].select.paginate([key: 'mtime', order: 'descending'], size: size, page: @page).map{|x| Pig.new(x)}
100
- @action = 'list'
101
- haml :index
106
+ haml :react
102
107
  end
103
108
 
104
- get('/meta/:key'){@p = Pig.find(params[:key]);haml :meta}
109
+ get '/recommend' do
110
+ haml :react
111
+ end
112
+
113
+ #get('/meta/:key'){@p = Pig.find(params[:key]);haml :meta}
114
+ get('/meta/:key') do
115
+ haml :react
116
+ end
105
117
  get('/sub/:key'){@p = Pig.find(params[:key]);haml :sub}
106
118
  get('/webvtt/:key'){@p = Pig.find(params[:key]); content_type :text; @p.webvtt}
107
119
  get '/delete/:key' do
@@ -140,6 +152,15 @@ EOF
140
152
  content_type :json
141
153
  {url: url}.to_json
142
154
  end
155
+ post '/gyazo/tweet' do
156
+ consumer_key = UserData.load session[:user_id], 'consumer_key'
157
+ consumer_secret = UserData.load session[:user_id], 'consumer_secret'
158
+ token = UserData.load session[:user_id], 'token'
159
+ token_secret = UserData.load session[:user_id], 'token_secret'
160
+ PigMediaServer::Gyazo.tweet params[:url], params[:comment], consumer_key, consumer_secret, token, token_secret, config()
161
+ true
162
+ end
163
+
143
164
 
144
165
  get '/remote' do
145
166
  if request.xhr? and params[:key]
@@ -171,18 +192,41 @@ EOF
171
192
 
172
193
  post '/sessions' do
173
194
  session[:user_id] = params[:user_id]
195
+ p session
174
196
  redirect '/'
175
197
  end
176
198
 
177
- get('/hash'){content_type :json; hash().to_json}
178
- post('/hash'){PigMediaServer::UserData.save params[:json], session[:user_id], config['user_data_path']}
199
+ get '/tv' do
200
+ @action = 'list'
201
+ haml :tv
202
+ end
203
+
204
+ get '/tv/list' do
205
+ content_type :json
206
+ UserData.load(session[:user_id], 'tv-list').to_json
207
+ end
208
+
209
+ post '/tv/list' do
210
+ UserData.save(session[:user_id], 'tv-list', JSON.parse(params[:data]))
211
+ end
212
+
213
+ get('/data'){UserData.load(session[:user_id], params[:key])}
214
+ post('/data'){UserData.save(session[:user_id], params[:key], params[:value])}
215
+ get('/recents'){content_type :json; p session[:user_id];Recents.list(session[:user_id]).to_json}
216
+ post '/recents' do
217
+ JSON.parse(params[:data]).each{|k,v|
218
+ Recents.recent session[:user_id], k
219
+ }
220
+ 'true'
221
+ end
179
222
 
180
223
  get('/config'){haml :config}
181
224
  get('/book2.js'){content_type :js;erb :book2}
182
225
  get('/swipe.js'){content_type :js;erb :swipe}
183
226
  get('/*.css'){scss params[:splat].first.to_sym}
227
+ get('/bundle.js'){content_type :js; open(File::dirname(__FILE__)+"/views/bundle.js").read}
184
228
  get('/*.js'){coffee params[:splat].first.to_sym}
185
-
229
+
186
230
  post '/api/save' do
187
231
  key = Digest::MD5.hexdigest(params[:name]).to_s
188
232
  FileUtils.mkdir_p "#{config['user_data_path']}/api_data"
@@ -201,17 +245,34 @@ EOF
201
245
  post '/api/capapi' do
202
246
  record = Groonga['Files'][params[:key]]
203
247
  name = "#{rand(256**16).to_s(16)}.jpg"
204
- system "ffmpeg -ss #{params[:time]} -vframes 1 -i \"#{record.path}\" -f image2 #{config['gyazo_path']}/#{name}"
248
+ system "avconv -ss #{params[:time]} -i \"#{record.path}\" -f image2 -s 1280x720 -vframes 1 #{config['gyazo_path']}/#{name}"
249
+ #system "gm convert -resize 1280x720! #{config['gyazo_path']}/#{name} #{config['gyazo_path']}/#{name}"
205
250
  "#{config['gyazo_prefix']}/#{name}"
206
251
  end
207
252
 
253
+ get '/star' do
254
+ Stars.star(session[:user_id], params[:key])
255
+ redirect params[:href]
256
+ end
257
+
258
+ get '/stars' do
259
+ @page = params[:page].to_i < 1 ? 1 : params[:page].to_i
260
+ @action = 'list'
261
+ @list = Stars.list session[:user_id]
262
+ haml :index
263
+ end
264
+
208
265
 
209
266
  helpers do
210
267
  def config
211
268
  $config = Pit.get("Pig Media Server") unless $config
269
+ $config['page_title'] = 'Pig Media Server' unless $config['page_title']
212
270
  $config
213
271
  end
214
272
  def h str; CGI.escapeHTML str.to_s; end
273
+ def remote?
274
+ UserData.load(session[:user_id], 'remote')
275
+ end
215
276
  def partial(template, *args)
216
277
  options = args.last.is_a?(Hash) ? args.pop : {}
217
278
  options.merge!(:layout => false)
@@ -223,12 +284,9 @@ EOF
223
284
  haml(template, options)
224
285
  end
225
286
  end
226
- def hash
227
- if session[:user_id]
228
- return PigMediaServer::UserData.load session[:user_id], config['user_data_path']
229
- else
230
- return {}
231
- end
287
+
288
+ def star? key
289
+ Stars.star?(session[:user_id], key)
232
290
  end
233
291
 
234
292
  def markdown str
@@ -257,8 +315,15 @@ EOF
257
315
  "%.#{precision}f TB" % (number / 1099511627776)
258
316
  end.sub(/([0-9]\.\d*?)0+ /, '\1 ' ).sub(/\. /,' ').encode('UTF-8')
259
317
  rescue
260
- nil
318
+ ""
261
319
  end
320
+
321
+ def title
322
+ base = $config['page_title']
323
+ return "#{params[:query]} - #{base}" if params[:query]
324
+ return "#{@p.name} - #{base}" if @p
325
+ base
326
+ end
262
327
  end
263
328
  end
264
329
 
data/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "main": "javascript/main.js",
3
+ "description": "music",
4
+ "dependencies": {
5
+ "react": "",
6
+ "react-dom": "",
7
+ "moment": "",
8
+ "moment-timezone": "",
9
+ "jquery": ""
10
+ },
11
+ "devDependencies": {
12
+ "browser-sync": "",
13
+ "browserify": "",
14
+ "babelify": "",
15
+ "gulp-webserver": "",
16
+ "gulp": "3.9.0",
17
+ "gulp-babel": "",
18
+ "vinyl-source-stream": "",
19
+ "vinyl-buffer": "",
20
+ "babel": "",
21
+ "gulp-uglify": ""
22
+ }
23
+ }
@@ -36,4 +36,9 @@ Gem::Specification.new do |gem|
36
36
  gem.add_dependency 'builder'
37
37
  gem.add_dependency 'coffee-script'
38
38
  gem.add_dependency 'sinatra-flash'
39
+ gem.add_dependency 'twitter'
40
+ gem.add_dependency 'thor'
41
+ gem.add_dependency 'mechanize'
42
+ gem.add_dependency 'activesupport'
43
+
39
44
  end