etvnet-seek 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +18 -8
- data/README +1 -1
- data/Rakefile +27 -5
- data/VERSION +1 -1
- data/bin/etvnet-seek +8 -3
- data/etvnet-seek.gemspec +79 -42
- data/lib/etvnet_seek/accessor.rb +64 -0
- data/lib/etvnet_seek/commander.rb +37 -21
- data/lib/etvnet_seek/core/access_page.rb +23 -6
- data/lib/etvnet_seek/core/audio_page.rb +26 -0
- data/lib/etvnet_seek/core/best_hundred_page.rb +20 -0
- data/lib/etvnet_seek/core/browse_media_item.rb +1 -0
- data/lib/etvnet_seek/core/catalog_page.rb +26 -14
- data/lib/etvnet_seek/core/channels_page.rb +6 -2
- data/lib/etvnet_seek/core/group_media_item.rb +2 -0
- data/lib/etvnet_seek/core/group_page.rb +9 -23
- data/lib/etvnet_seek/core/home_page.rb +5 -2
- data/lib/etvnet_seek/core/items_page.rb +140 -0
- data/lib/etvnet_seek/core/items_page_factory.rb +47 -0
- data/lib/etvnet_seek/core/login_page.rb +3 -1
- data/lib/etvnet_seek/core/media_info.rb +3 -18
- data/lib/etvnet_seek/core/media_item.rb +10 -2
- data/lib/etvnet_seek/core/media_page.rb +54 -27
- data/lib/etvnet_seek/core/new_item.rb +2 -0
- data/lib/etvnet_seek/core/new_items_page.rb +4 -1
- data/lib/etvnet_seek/core/page.rb +2 -0
- data/lib/etvnet_seek/core/premiere_page.rb +7 -0
- data/lib/etvnet_seek/core/radio_page.rb +23 -0
- data/lib/etvnet_seek/core/search_page.rb +3 -33
- data/lib/etvnet_seek/core/service_call.rb +34 -6
- data/lib/etvnet_seek/core/top_this_week_page.rb +20 -0
- data/lib/etvnet_seek/etvnet_seek.rb +1 -4
- data/lib/etvnet_seek/main.rb +113 -84
- data/spec/etvnet_seek_spec.rb +10 -8
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/pages_spec.rb +77 -0
- metadata +182 -32
- data/lib/etvnet_seek/core/base_page.rb +0 -43
- data/lib/etvnet_seek/core/page_factory.rb +0 -51
@@ -18,8 +18,16 @@ class MediaItem
|
|
18
18
|
false
|
19
19
|
end
|
20
20
|
|
21
|
-
def has_media_links?
|
22
|
-
|
21
|
+
# def has_media_links?
|
22
|
+
# page = Page.new link
|
23
|
+
#
|
24
|
+
# page.document.css("b a.media_file").size > 0
|
25
|
+
# end
|
26
|
+
|
27
|
+
def access_page?
|
28
|
+
page = Page.new link
|
29
|
+
|
30
|
+
page.document.css(".start-video start-movie").size > 0
|
23
31
|
end
|
24
32
|
|
25
33
|
def ==(object)
|
@@ -1,41 +1,68 @@
|
|
1
|
-
|
1
|
+
require 'etvnet_seek/core/items_page'
|
2
|
+
require 'etvnet_seek/core/browse_media_item'
|
3
|
+
|
4
|
+
class MediaPage < ItemsPage
|
5
|
+
|
2
6
|
def items
|
3
7
|
list = []
|
4
8
|
|
5
9
|
document.css(".conteiner table#table-onecolumn tr").each do |item|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
folder = true
|
20
|
-
else
|
10
|
+
unless item.css("td[1]").text.empty?
|
11
|
+
showtime = item.css("td[1]").text.strip
|
12
|
+
name = item.css("td[2]").text.strip
|
13
|
+
rating_image = item.css("td[3] img").at(0) ? item.css("td[3] img").at(0).attributes['src'].value.strip : ""
|
14
|
+
rating = item.css("td[4]") ? item.css("td[4]").text.strip : ""
|
15
|
+
duration = item.css("td[5]") ? item.css("td[5]").text.strip : ""
|
16
|
+
year = item.css("td[6]") ? item.css("td[6]").text.strip : ""
|
17
|
+
channel = item.css("td[7]") ? item.css("td[7]").text.strip : ""
|
18
|
+
|
19
|
+
link = item.css("td[2] a").at(0).attributes['href'].value
|
20
|
+
|
21
|
+
additional_info = additional_info(item.css("td[2] a").at(0), 2)
|
22
|
+
|
21
23
|
folder = false
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
record.channel = channel
|
30
|
-
record.rating_image = rating_image
|
31
|
-
record.rating = rating
|
25
|
+
if not additional_info.nil? and additional_info.strip.size > 0
|
26
|
+
if(additional_info.strip.scan(/\((\d*)(.*)\)/)).size > 0
|
27
|
+
folder = true
|
28
|
+
end
|
29
|
+
end
|
32
30
|
|
33
|
-
|
31
|
+
record = BrowseMediaItem.new(name, link)
|
32
|
+
record.folder = folder
|
33
|
+
record.showtime = showtime
|
34
|
+
record.year = year
|
35
|
+
record.duration = duration
|
36
|
+
record.channel = channel
|
37
|
+
record.rating_image = rating_image
|
38
|
+
record.rating = rating
|
39
|
+
|
40
|
+
list << record
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
44
|
list
|
37
|
-
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def info_movie_breadcrumbs
|
48
|
+
document.css(".path_movie_info_menu").inner_html
|
49
|
+
end
|
50
|
+
|
51
|
+
def info_movie_screenshots
|
52
|
+
collect_images ".all-inner-pages .screenshots"
|
53
|
+
end
|
54
|
+
|
55
|
+
def info_movie_descripton
|
56
|
+
document.css(".all-inner-pages .description")[0].children.at(0).text
|
57
|
+
end
|
58
|
+
|
59
|
+
def info_movie_additional_info
|
60
|
+
document.css(".all-inner-pages .description")[1].inner_html
|
61
|
+
end
|
38
62
|
|
63
|
+
def info_movie_additional_info2
|
64
|
+
document.css(".all-inner-pages .acc_container").inner_html
|
65
|
+
end
|
39
66
|
end
|
40
67
|
|
41
68
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'etvnet_seek/core/items_page'
|
2
|
+
require 'etvnet_seek/core/media_item'
|
3
|
+
|
4
|
+
class RadioPage < ItemsPage
|
5
|
+
AUDIO_URL = BASE_URL + "/audio/"
|
6
|
+
|
7
|
+
def initialize url = AUDIO_URL
|
8
|
+
super(url)
|
9
|
+
end
|
10
|
+
|
11
|
+
def items
|
12
|
+
list = []
|
13
|
+
|
14
|
+
document.css("#sidebar #slideshow1 .active a").each do |item|
|
15
|
+
text = item.css("img").at(0).attributes["title"].value.strip
|
16
|
+
href = item['href']
|
17
|
+
|
18
|
+
list << MediaItem.new(text, href)
|
19
|
+
end
|
20
|
+
|
21
|
+
list
|
22
|
+
end
|
23
|
+
end
|
@@ -1,42 +1,12 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
|
3
|
-
|
3
|
+
require 'etvnet_seek/core/catalog_page'
|
4
|
+
|
5
|
+
class SearchPage < CatalogPage
|
4
6
|
SEARCH_URL = BASE_URL + "/search/"
|
5
7
|
|
6
8
|
def initialize(params)
|
7
9
|
super("#{SEARCH_URL}?q=#{CGI.escape(*params)}")
|
8
10
|
end
|
9
11
|
|
10
|
-
def items
|
11
|
-
list = []
|
12
|
-
|
13
|
-
document.css(".conteiner #results #table-onecolumn tr").each_with_index do |item, index|
|
14
|
-
next if index == 0
|
15
|
-
|
16
|
-
showtime = item.css("td[1]").text.strip
|
17
|
-
rating_image = item.css("td[2] img").at(0) ? item.css("td[2] img").at(0).attributes['src'].value.strip : ""
|
18
|
-
rating = item.css("td[3]") ? item.css("td[3]").text.strip : ""
|
19
|
-
name = item.css("td[4]").text.strip
|
20
|
-
duration = item.css("td[5]") ? item.css("td[5]").text.strip : ""
|
21
|
-
link = item.css("td[4] a").at(0)
|
22
|
-
|
23
|
-
href = link.attributes['href'].value
|
24
|
-
|
25
|
-
amount_expr = name.scan(%r{(.*)+\((\d*)+ (.*)+\)})[0]
|
26
|
-
|
27
|
-
folder = (not amount_expr.nil? and amount_expr.size > 1) ? true : false
|
28
|
-
|
29
|
-
record = BrowseMediaItem.new(name, href)
|
30
|
-
record.folder = folder
|
31
|
-
record.showtime = showtime
|
32
|
-
record.duration = duration
|
33
|
-
#record.channel = channel
|
34
|
-
record.rating_image = rating_image
|
35
|
-
record.rating = rating
|
36
|
-
|
37
|
-
list << record
|
38
|
-
end
|
39
|
-
|
40
|
-
list
|
41
|
-
end
|
42
12
|
end
|
@@ -1,5 +1,19 @@
|
|
1
1
|
require 'open-uri'
|
2
2
|
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
# Lengthen timeout in Net::HTTP
|
6
|
+
module Net
|
7
|
+
class HTTP
|
8
|
+
alias old_initialize initialize
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
old_initialize(*args)
|
12
|
+
@read_timeout = 3*60 # 3 minutes
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
3
17
|
class ServiceCall
|
4
18
|
attr_reader :url
|
5
19
|
|
@@ -8,20 +22,34 @@ class ServiceCall
|
|
8
22
|
end
|
9
23
|
|
10
24
|
def get
|
11
|
-
open(url)
|
25
|
+
open(url, "User-Agent" => "Ruby/#{RUBY_VERSION}")
|
12
26
|
end
|
13
27
|
|
14
|
-
def post params, headers
|
15
|
-
request = Net::HTTP::Post.new(url, headers)
|
16
|
-
|
28
|
+
def post params, headers, url = @url
|
29
|
+
request = Net::HTTP::Post.new(url, headers.merge({"User-Agent" => "Ruby/#{RUBY_VERSION}"}))
|
17
30
|
request.set_form_data(params)
|
31
|
+
#request.basic_auth(un, pw)
|
32
|
+
#"Content-Type"=>"application/x-www-form-urlencoded",
|
33
|
+
#"Authorization" => "Basic " + Base64::encode64("account:password")
|
34
|
+
response = request(request, url)
|
18
35
|
|
19
|
-
|
36
|
+
if response.class == Net::HTTPMovedPermanently
|
37
|
+
response = handle_redirect response['location'], params, headers
|
38
|
+
end
|
39
|
+
|
40
|
+
response
|
20
41
|
end
|
21
42
|
|
22
43
|
protected
|
23
44
|
|
24
|
-
def
|
45
|
+
def handle_redirect url, params, headers
|
46
|
+
request = Net::HTTP::Post.new(url, headers.merge({"User-Agent" => "Ruby/#{RUBY_VERSION}"}))
|
47
|
+
request.set_form_data(params)
|
48
|
+
|
49
|
+
request(request, url)
|
50
|
+
end
|
51
|
+
|
52
|
+
def request request, url
|
25
53
|
uri = URI.parse(url)
|
26
54
|
|
27
55
|
connection = Net::HTTP.new(uri.host, uri.port)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'etvnet_seek/core/group_page'
|
2
|
+
require 'etvnet_seek/core/group_media_item'
|
3
|
+
|
4
|
+
class TopThisWeekPage < GroupPage
|
5
|
+
def items
|
6
|
+
parent = document.css(".conteiner .coming-soon").at(0).parent
|
7
|
+
parent.css("ul.best-list li")
|
8
|
+
|
9
|
+
list = get_typical_items("ul.best-list li", parent)
|
10
|
+
|
11
|
+
node = parent.css("ul.best-list").at(0).next
|
12
|
+
|
13
|
+
unless node.nil?
|
14
|
+
link = node.attributes['href'].value
|
15
|
+
text = node.children.at(0).content
|
16
|
+
|
17
|
+
list << GroupMediaItem.new(text, link)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -3,8 +3,5 @@ require 'rubygems' unless RUBY_VERSION =~ /1.9.*/
|
|
3
3
|
$:.unshift(File.dirname(__FILE__)) unless
|
4
4
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
5
5
|
|
6
|
-
require 'etvnet_seek/
|
7
|
-
|
8
|
-
require 'etvnet_seek/cookie_helper'
|
9
|
-
require 'etvnet_seek/link_info'
|
6
|
+
require 'etvnet_seek/main'
|
10
7
|
|
data/lib/etvnet_seek/main.rb
CHANGED
@@ -4,120 +4,149 @@ require 'date'
|
|
4
4
|
|
5
5
|
require 'etvnet_seek/commander'
|
6
6
|
require 'etvnet_seek/user_selection'
|
7
|
+
require 'etvnet_seek/accessor'
|
7
8
|
require 'runglish'
|
8
9
|
|
10
|
+
require 'etvnet_seek/link_info'
|
11
|
+
require 'etvnet_seek/core/items_page_factory'
|
12
|
+
require 'etvnet_seek/core/items_page'
|
13
|
+
|
9
14
|
class Main
|
10
15
|
COOKIE_FILE_NAME = ENV['HOME'] + "/.etvnet-seek"
|
11
16
|
|
12
17
|
def initialize
|
13
|
-
@cookie_helper = CookieHelper.new COOKIE_FILE_NAME
|
14
18
|
@commander = Commander.new
|
19
|
+
@accessor = Accessor.new COOKIE_FILE_NAME, lambda { get_credentials }
|
15
20
|
end
|
16
21
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
+
def process *params
|
23
|
+
mode = @commander.get_initial_mode
|
24
|
+
|
25
|
+
case mode
|
26
|
+
when /(search|translit)/ then
|
27
|
+
keywords = read_keywords(*params)
|
28
|
+
puts "Keywords: #{keywords}" if @commander.translit_mode?
|
29
|
+
|
30
|
+
process_folder "search", keywords
|
31
|
+
when 'main' then
|
32
|
+
main
|
33
|
+
when 'channels' then
|
34
|
+
channels
|
35
|
+
when 'catalog' then
|
36
|
+
process_folder "catalog"
|
37
|
+
when 'best_hundred' then
|
38
|
+
best_hundred
|
39
|
+
when 'top_this_week' then
|
40
|
+
top_this_week
|
41
|
+
when 'premiere' then
|
42
|
+
process_folder "premiere"
|
43
|
+
when 'new_items' then
|
44
|
+
process_folder "new_items"
|
22
45
|
end
|
23
|
-
|
24
|
-
process @commander.get_initial_mode, params
|
25
46
|
end
|
26
47
|
|
27
|
-
def
|
28
|
-
|
48
|
+
def main
|
49
|
+
process_items "main" do |item, _|
|
50
|
+
case item.link
|
51
|
+
when /tv_channels/ then
|
52
|
+
channels
|
53
|
+
when /(aired_today|catalog)/ then
|
54
|
+
process_folder "media", item.link
|
55
|
+
when /audio/ then
|
56
|
+
audio item.link
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
29
60
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
item = params[0]
|
34
|
-
cookie = page.login(*get_credentials)
|
61
|
+
def channels
|
62
|
+
process_items "channels" do |item, user_selection|
|
63
|
+
link = user_selection.catalog? ? item.catalog_link : item.link
|
35
64
|
|
36
|
-
|
65
|
+
process_folder "media", link
|
66
|
+
end
|
67
|
+
end
|
37
68
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
if items.size > 0
|
43
|
-
display_items items
|
44
|
-
display_bottom_menu_part(mode)
|
45
|
-
|
46
|
-
user_selection = read_user_selection items
|
47
|
-
|
48
|
-
if not user_selection.quit?
|
49
|
-
current_item = items[user_selection.index]
|
50
|
-
if mode == 'main'
|
51
|
-
case current_item.link
|
52
|
-
when '/' then
|
53
|
-
process("main")
|
54
|
-
when /aired_today/ then
|
55
|
-
process('media', current_item.link)
|
56
|
-
when /catalog/ then
|
57
|
-
process('media', current_item.link)
|
58
|
-
when /tv_channels/ then
|
59
|
-
process('channels', current_item.link)
|
60
|
-
end
|
61
|
-
elsif mode == 'channels'
|
62
|
-
p user_selection.catalog?
|
63
|
-
if user_selection.catalog?
|
64
|
-
process('media', current_item.catalog_link)
|
65
|
-
else
|
66
|
-
process('media', current_item.link)
|
67
|
-
end
|
68
|
-
elsif mode == 'new_items'
|
69
|
-
process('access', current_item)
|
70
|
-
elsif mode == 'premiere'
|
71
|
-
process('access', current_item)
|
72
|
-
elsif mode == 'catalog'
|
73
|
-
p 'catalog'
|
74
|
-
process('media', current_item.link)
|
75
|
-
else # media
|
76
|
-
if current_item.folder? or current_item.link =~ /(catalog|tv_channel)/
|
77
|
-
process('media', current_item.link)
|
78
|
-
else
|
79
|
-
process("access", current_item)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
69
|
+
def best_hundred
|
70
|
+
process_items "best_hundred" do |item, _|
|
71
|
+
process_group item, item.link =~ /best100/
|
84
72
|
end
|
85
73
|
end
|
86
74
|
|
87
|
-
def
|
88
|
-
|
75
|
+
def top_this_week
|
76
|
+
process_items "top_this_week" do |item, _|
|
77
|
+
process_group item, item.link =~ /top_this_week/
|
78
|
+
end
|
79
|
+
end
|
89
80
|
|
90
|
-
|
91
|
-
|
81
|
+
def process_group item, next_group
|
82
|
+
if next_group
|
83
|
+
process_items "media", item.link do |media_item, _|
|
84
|
+
access_or_media item, (folder?(media_item) or not media_item.access_page?)
|
85
|
+
end
|
92
86
|
else
|
93
|
-
|
94
|
-
|
87
|
+
access_or_media item, (folder?(item) or not item.access_page?)
|
88
|
+
end
|
89
|
+
end
|
95
90
|
|
96
|
-
|
97
|
-
|
91
|
+
def folder? item
|
92
|
+
item.link =~ /(catalog|tv_channel)/ || item.folder?
|
93
|
+
end
|
98
94
|
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
def process_folder name, *params
|
96
|
+
process_items name, *params do |item, _|
|
97
|
+
access_or_media item, folder?(item)
|
98
|
+
end
|
99
|
+
end
|
102
100
|
|
103
|
-
|
104
|
-
|
101
|
+
def audio root
|
102
|
+
process_items "audio", root do |item1, _|
|
103
|
+
process_items "radio", item1.link do |item2, _|
|
104
|
+
media_info = MediaInfo.new item2.link
|
105
|
+
LinkInfo.new(item2, media_info)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
105
109
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
+
def access_or_media item, folder
|
111
|
+
if folder
|
112
|
+
process_folder "media", item.link
|
113
|
+
else
|
114
|
+
result = @accessor.access item
|
115
|
+
|
116
|
+
while(@accessor.try_again? or result.nil?) do
|
117
|
+
result = @accessor.access item
|
110
118
|
end
|
119
|
+
|
120
|
+
result
|
111
121
|
end
|
112
122
|
end
|
113
123
|
|
114
124
|
def get_credentials
|
115
|
-
username = ask("Enter username : "
|
116
|
-
password = ask("Enter password : "
|
125
|
+
username = ask("Enter username : ")
|
126
|
+
password = ask("Enter password : ") { |q| q.echo = '*' }
|
117
127
|
|
118
128
|
[username, password]
|
119
129
|
end
|
120
130
|
|
131
|
+
def process_items mode, *params
|
132
|
+
page = ItemsPageFactory.create mode, *params
|
133
|
+
|
134
|
+
items = page.items
|
135
|
+
|
136
|
+
if items.size > 0
|
137
|
+
display_items items
|
138
|
+
display_bottom_menu_part(mode)
|
139
|
+
|
140
|
+
user_selection = read_user_selection items
|
141
|
+
|
142
|
+
if not user_selection.quit?
|
143
|
+
current_item = items[user_selection.index]
|
144
|
+
|
145
|
+
yield(current_item, user_selection) if block_given?
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
121
150
|
def display_items items
|
122
151
|
if items.size == 0
|
123
152
|
puts "Empty search result."
|
@@ -146,13 +175,13 @@ class Main
|
|
146
175
|
def read_keywords input
|
147
176
|
keywords = input
|
148
177
|
|
149
|
-
if(keywords.strip.size == 0)
|
178
|
+
if (keywords.strip.size == 0)
|
150
179
|
while keywords.strip.size == 0
|
151
180
|
keywords = ask("Keywords: ")
|
152
181
|
end
|
153
182
|
end
|
154
183
|
|
155
|
-
if RUBY_PLATFORM =~ /mswin32/ or @commander.
|
184
|
+
if RUBY_PLATFORM =~ /mswin32/ or @commander.translit_mode?
|
156
185
|
keywords = Runglish::LatToRusConverter.new.transliterate(keywords)
|
157
186
|
end
|
158
187
|
|
@@ -161,7 +190,7 @@ class Main
|
|
161
190
|
|
162
191
|
def read_user_selection items
|
163
192
|
user_selection = UserSelection.new
|
164
|
-
|
193
|
+
|
165
194
|
while true
|
166
195
|
user_selection.parse(ask("Select the number: "))
|
167
196
|
|