serial-watcher 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/bin/serial-watcher +13 -0
- data/serial-watcher.gemspec +19 -0
- data/src/Gemfile +8 -0
- data/src/episode.rb +12 -0
- data/src/fs.rb +103 -0
- data/src/gui/list_model.rb +35 -0
- data/src/gui/list_view.rb +46 -0
- data/src/gui/main.rb +224 -0
- data/src/gui/meta_dialog.rb +42 -0
- data/src/gui/settings_dialog.rb +44 -0
- data/src/gui/title_box.rb +73 -0
- data/src/gui/torrent_panel.rb +42 -0
- data/src/main.rb +53 -0
- data/src/meta.rb +43 -0
- data/src/player.rb +58 -0
- data/src/plugins/torrent/main.rb +29 -0
- data/src/plugins/torrent/torrentz.rb +25 -0
- data/src/plugins/torrent/tpb.rb +25 -0
- data/src/serial.rb +27 -0
- data/src/status.rb +86 -0
- data/static/images/app.png +0 -0
- data/static/images/dash.png +0 -0
- data/static/images/fullscreen.png +0 -0
- data/static/images/round.png +0 -0
- data/tmp/install.rb +38 -0
- data/tmp/sendkey.sh +5 -0
- data/tmp/vimsession.vim +2348 -0
- metadata +169 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
module Gui
|
3
|
+
class MetaDialog < Gtk::Dialog
|
4
|
+
|
5
|
+
type_register
|
6
|
+
def initialize(hash)
|
7
|
+
serial = hash[:serial]
|
8
|
+
hash = nil
|
9
|
+
super
|
10
|
+
|
11
|
+
|
12
|
+
set_title "Serial Meta Edit"
|
13
|
+
add_buttons [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_OK],
|
14
|
+
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL]
|
15
|
+
has_separator = false
|
16
|
+
|
17
|
+
table = Gtk::Table.new 5, 2, true
|
18
|
+
table.border_width = 10
|
19
|
+
|
20
|
+
entry = Gtk::Entry.new
|
21
|
+
@status = Status.instance
|
22
|
+
|
23
|
+
# 1st row
|
24
|
+
label = Gtk::Label.new("Name: ")
|
25
|
+
@name_entry = Gtk::Entry.new
|
26
|
+
@name_entry.text = serial.meta.name || serial.name
|
27
|
+
table.attach label, 0, 1, 0, 1
|
28
|
+
table.attach @name_entry, 1, 2, 0, 1
|
29
|
+
|
30
|
+
# 2nd row
|
31
|
+
|
32
|
+
vbox.add(table)
|
33
|
+
show_all
|
34
|
+
end
|
35
|
+
|
36
|
+
def values
|
37
|
+
data = {
|
38
|
+
:name => @name_entry.text
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
module Gui
|
3
|
+
class SettingsDialog < Gtk::Dialog
|
4
|
+
|
5
|
+
type_register
|
6
|
+
def initialize()
|
7
|
+
super
|
8
|
+
set_title "Serial Watcher Settings"
|
9
|
+
add_buttons [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_OK],
|
10
|
+
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL]
|
11
|
+
has_separator = false
|
12
|
+
|
13
|
+
table = Gtk::Table.new 5, 2, true
|
14
|
+
table.border_width = 10
|
15
|
+
|
16
|
+
@status = Status.instance
|
17
|
+
@original_path = @status.data_dir
|
18
|
+
|
19
|
+
entry = Gtk::Entry.new
|
20
|
+
|
21
|
+
# 1st row
|
22
|
+
label = Gtk::Label.new("Serials directory: ")
|
23
|
+
@path_chooser = Gtk::FileChooserButton.new( "Choose a Folder", Gtk::FileChooser::ACTION_SELECT_FOLDER)
|
24
|
+
@path_chooser.current_folder = @status.data_dir
|
25
|
+
table.attach label, 0, 1, 0, 1
|
26
|
+
table.attach @path_chooser, 1, 2, 0, 1
|
27
|
+
|
28
|
+
# 2nd row
|
29
|
+
|
30
|
+
vbox.add(table)
|
31
|
+
show_all
|
32
|
+
end
|
33
|
+
|
34
|
+
def path_changed?
|
35
|
+
@original_path != @path_chooser.current_folder
|
36
|
+
end
|
37
|
+
|
38
|
+
def values
|
39
|
+
data = {
|
40
|
+
:path => @path_chooser.current_folder
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
require 'serial'
|
3
|
+
require 'fs'
|
4
|
+
|
5
|
+
module Gui
|
6
|
+
class TitleBox < Gtk::VBox
|
7
|
+
type_register
|
8
|
+
attr_accessor :serials
|
9
|
+
|
10
|
+
signal_new("title_changed", GLib::Signal::RUN_FIRST, nil, nil, Serial)
|
11
|
+
signal_new("loaded", GLib::Signal::RUN_FIRST, nil, nil, false)
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@colormap = Gtk::Widget.default_colormap
|
15
|
+
@fs = Fs.instance
|
16
|
+
@status = Status.instance
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def clear
|
21
|
+
self.each_forall do |e|
|
22
|
+
remove(e) if e.class.to_s == "Gtk::Button"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def load(dir = @status.data_dir)
|
27
|
+
clear
|
28
|
+
|
29
|
+
@fs.init dir
|
30
|
+
series = @fs.series || []
|
31
|
+
series.each do |serial|
|
32
|
+
|
33
|
+
# button
|
34
|
+
button = Gtk::Button.new " #{serial.name} "
|
35
|
+
button.use_stock = true
|
36
|
+
button.set_xalign 0.0
|
37
|
+
button.set_image Gtk::Image.new( serial.image || File.join($STATIC_PATH, 'images/dash.png') )
|
38
|
+
button.set_image_position Gtk::POS_LEFT
|
39
|
+
|
40
|
+
button.signal_connect "clicked" do
|
41
|
+
self.modify_current_button button
|
42
|
+
self.signal_emit( "title_changed", serial )
|
43
|
+
end
|
44
|
+
|
45
|
+
if serial.path == @status.get_last_serial
|
46
|
+
button.signal_emit "clicked"
|
47
|
+
end
|
48
|
+
|
49
|
+
pack_start button, false, false, 3
|
50
|
+
end
|
51
|
+
self.show_all
|
52
|
+
self.signal_emit( "loaded" , false)
|
53
|
+
end
|
54
|
+
|
55
|
+
def modify_current_button button
|
56
|
+
self.each_forall do |btn|
|
57
|
+
if btn.class.to_s == "Gtk::Button"
|
58
|
+
btn.modify_bg(Gtk::STATE_NORMAL, nil)
|
59
|
+
btn.modify_bg(Gtk::STATE_PRELIGHT, nil)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
button.modify_bg(Gtk::STATE_NORMAL, Gdk::Color.new(45535, 45535, 65535))
|
63
|
+
button.modify_bg(Gtk::STATE_PRELIGHT, Gdk::Color.new(40535, 40535, 65535))
|
64
|
+
end
|
65
|
+
|
66
|
+
def signal_do_title_changed(arg)
|
67
|
+
end
|
68
|
+
|
69
|
+
def signal_do_loaded(arg)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Gui
|
5
|
+
class TorrentPanel < Gtk::VBox
|
6
|
+
|
7
|
+
type_register
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
height_request = 50
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear
|
15
|
+
each_forall do |e| remove(e) end
|
16
|
+
end
|
17
|
+
|
18
|
+
def load(serial)
|
19
|
+
clear
|
20
|
+
|
21
|
+
Thread.new do
|
22
|
+
@torrent = ::Torrent::Torrentz.instance
|
23
|
+
@torrent.load serial.meta.name
|
24
|
+
@torrent.get_last_feeds.each do |torrent|
|
25
|
+
|
26
|
+
torrent_link = Gtk::LinkButton.new torrent[:url], "#{torrent[:date]} / #{torrent[:name]}"
|
27
|
+
|
28
|
+
torrent_link.set_alignment 0, 0.5
|
29
|
+
torrent_link.signal_connect "clicked" do |link_btn|
|
30
|
+
Thread.new do
|
31
|
+
`chromium #{link_btn.uri}`
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
pack_start_defaults torrent_link#, true, true #false, false
|
36
|
+
|
37
|
+
end
|
38
|
+
show_all
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/src/main.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
$LOAD_PATH << '.'
|
3
|
+
|
4
|
+
require 'lockfile'
|
5
|
+
require 'gui/main'
|
6
|
+
|
7
|
+
$DATADIR = ''
|
8
|
+
$INITIAL_SERIAL = ""
|
9
|
+
$INITIAL_EPISODE = 0
|
10
|
+
|
11
|
+
$DEBUG = false
|
12
|
+
#$DEBUG = true
|
13
|
+
|
14
|
+
class SerialWatcher
|
15
|
+
def initialize
|
16
|
+
begin
|
17
|
+
Lockfile("/tmp/serial-watcher.lock", :retries => 0, :debug => $DEBUG, :poll_retries => 1) do
|
18
|
+
Gtk.init
|
19
|
+
window = Gui::Main.new
|
20
|
+
window.show_all
|
21
|
+
Gtk.main
|
22
|
+
end
|
23
|
+
rescue Lockfile::MaxTriesLockError
|
24
|
+
notify "Another instance is running"
|
25
|
+
self.raise_window
|
26
|
+
end
|
27
|
+
self.quit
|
28
|
+
end
|
29
|
+
|
30
|
+
def raise_window
|
31
|
+
begin
|
32
|
+
window_id = `xdotool search --name "Serial\ Watcher"`
|
33
|
+
`xdotool windowraise #{window_id}`
|
34
|
+
`xdotool windowfocus #{window_id}`
|
35
|
+
rescue
|
36
|
+
notify "you need to install xdotool to raise opened window"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def quit
|
41
|
+
log "Quiting .."
|
42
|
+
Kernel.exit(1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def notify(message)
|
47
|
+
`notify-send '#{message}'`
|
48
|
+
end
|
49
|
+
|
50
|
+
def log(message)
|
51
|
+
puts message
|
52
|
+
end
|
53
|
+
|
data/src/meta.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
class Meta
|
3
|
+
def initialize(serial)
|
4
|
+
@serial = serial
|
5
|
+
end
|
6
|
+
|
7
|
+
def name
|
8
|
+
@name ||= (@name.nil? ? @serial.name : @name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
"#{@serial.path}/.meta"
|
13
|
+
end
|
14
|
+
|
15
|
+
def meta_data
|
16
|
+
data = {
|
17
|
+
:name => name
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_file
|
22
|
+
begin
|
23
|
+
File.open(path, 'w') { |f| f.write( meta_data.to_yaml ) }
|
24
|
+
rescue
|
25
|
+
puts "cannot create meta-file"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_file
|
30
|
+
meta = File.exists?(path) ? YAML.load(File.open(path)) : meta_data
|
31
|
+
meta_data.each { |key, value|
|
32
|
+
eval("@#{key} = ?", meta.try('[]', key))
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_file meta
|
37
|
+
meta_data.each do |key, value|
|
38
|
+
eval("@#{key} = ?", meta.try('[]', key))
|
39
|
+
end
|
40
|
+
create_file
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
data/src/player.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'gtk2'
|
3
|
+
|
4
|
+
require 'status'
|
5
|
+
|
6
|
+
class Player < Gtk::Object
|
7
|
+
|
8
|
+
include Singleton
|
9
|
+
type_register
|
10
|
+
|
11
|
+
attr_accessor :status
|
12
|
+
|
13
|
+
signal_new("playing_ended", GLib::Signal::RUN_FIRST, nil, nil, String)
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@status = Status.instance
|
18
|
+
end
|
19
|
+
|
20
|
+
def play_episode episode
|
21
|
+
@status.save_status episode
|
22
|
+
begin
|
23
|
+
@thr = Thread.new do
|
24
|
+
|
25
|
+
Thread.abort_on_exception = true
|
26
|
+
#s = `mplayer -identify -fs \'#{episode.path}\' 2>&1 | tail -n 1`
|
27
|
+
`killall mplayer 2>&1 > /dev/null`
|
28
|
+
s = `mplayer -identify \'#{episode.path}\' #{"-fs" if @status.data[:fullscreen]} 2>&1 | tail -n 1`
|
29
|
+
if s == "ID_EXIT=EOF\n"
|
30
|
+
signal_emit("playing_ended", "param")
|
31
|
+
#raise "playing ended"
|
32
|
+
end
|
33
|
+
|
34
|
+
Thread.exit
|
35
|
+
end
|
36
|
+
|
37
|
+
Thread.new do
|
38
|
+
sleep 2
|
39
|
+
4.times do
|
40
|
+
# TODO fix it all
|
41
|
+
m_id=`xwininfo -name MPlayer |grep 'Window id:' |cut -d" " -f4`.strip
|
42
|
+
cmd = "xdotool key --window #{m_id} 114"
|
43
|
+
`#{cmd}`
|
44
|
+
end
|
45
|
+
Thread.exit
|
46
|
+
end
|
47
|
+
|
48
|
+
rescue
|
49
|
+
puts "resque"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def signal_do_playing_ended param
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require 'simple-rss'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
module Torrent
|
7
|
+
class Main
|
8
|
+
attr_reader :url, :rss
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@data = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def rss_load
|
16
|
+
@rss = @data[@name] || (@data[@name] = SimpleRSS.parse open(@url) if @url)
|
17
|
+
end
|
18
|
+
|
19
|
+
def human_format
|
20
|
+
raise "Method need to be overloaded"
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def get_last_feeds(num = 5, trim = 40)
|
25
|
+
return [] if not @rss
|
26
|
+
human_format(@rss.channel.items.sort{|b,a| a[:pubDate] <=> b[:pubDate]}[0,5], trim)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'date'
|
3
|
+
require 'plugins/torrent/main'
|
4
|
+
|
5
|
+
module Torrent
|
6
|
+
class Torrentz < Main
|
7
|
+
|
8
|
+
def load(name)
|
9
|
+
@name = name
|
10
|
+
@url = ("http://torrentz.eu/feed?q=#{CGI.escape(name)}" if name) || nil
|
11
|
+
rss_load if @url
|
12
|
+
end
|
13
|
+
|
14
|
+
def human_format list, trim
|
15
|
+
list.map do |item|
|
16
|
+
nitem = {}
|
17
|
+
nitem[:name] = item[:title].length > trim ? "#{item[:title][0, trim]}.." : item[:title]
|
18
|
+
nitem[:date] = "#{(Date.today - item[:pubDate].to_date).to_i} days ago"
|
19
|
+
nitem[:url] = item[:link]
|
20
|
+
nitem
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'date'
|
3
|
+
require 'plugins/torrent/main'
|
4
|
+
|
5
|
+
module Torrent
|
6
|
+
class TPB < Main
|
7
|
+
|
8
|
+
def load(name)
|
9
|
+
@name = name
|
10
|
+
@url = ""#http://torrentz.eu/feed?q=#{CGI.escape(name)}"
|
11
|
+
rss_load
|
12
|
+
end
|
13
|
+
|
14
|
+
def human_format list, trim
|
15
|
+
list.map do |item|
|
16
|
+
nitem = {}
|
17
|
+
nitem[:name] = "#{item[:title][0, trim]}.." if item[:title].length > trim
|
18
|
+
nitem[:date] = item[:pubDate]
|
19
|
+
nitem[:url] = item[:link]
|
20
|
+
nitem
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|