appbox-octopress 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f56277fa6cf5fef3f50dc3c6dc555ac65184d5cc
4
+ data.tar.gz: c3d11e6776716699fb6d032d02f38dda5742b6dd
5
+ SHA512:
6
+ metadata.gz: 4f479dc3b47a10d1487c0c37a67b6134f5ac1a0bda3c02413827bea8dd9df948a604f44bd7db7c73ae1f88ca1b3f5600440eb1a8772d285ee4e52339a7d2854a
7
+ data.tar.gz: 30cc3628dff45045a5181c5d85e7eafcb90cf74cd1e34f9cacd446f049cc7d21abce97d867a5150c81d194d5ed42f48ef551054674d7a4c987c92076e56de189
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/appbox_octopress')
@@ -0,0 +1,12 @@
1
+ require 'fileutils'
2
+ require File.join(File.dirname(__FILE__) + '/appbox_octopress/utilities')
3
+
4
+ if ARGV.length == 1 && ARGV[0] == 'install'
5
+ AppboxOctopress::Utilities.install
6
+ puts "Appbox Octopress installed"
7
+ elsif ARGV.length == 1 && ARGV[0] == 'remove'
8
+ AppboxOctopress::Utilities.remove
9
+ puts "Appbox Octopress removed"
10
+ else
11
+ puts "Usage: appbox-octopress [install|remove]"
12
+ end
@@ -0,0 +1,39 @@
1
+ module AppboxOctopress
2
+ module Utilities
3
+ PLUGINS_DIR = File.expand_path(File.dirname(__FILE__) + '/../../templates/plugins')
4
+ CSS_DIR = File.expand_path(File.dirname(__FILE__) + '/../../templates/css')
5
+
6
+ def self.install
7
+ FileUtils.copy_file plugin_path, plugin_destination
8
+ FileUtils.copy_file css_path, css_destination
9
+ add_stylesheet
10
+ end
11
+
12
+ def self.remove
13
+ FileUtils.rm plugin_destination
14
+ FileUtils.rm css_destination
15
+ end
16
+
17
+ protected
18
+
19
+ def self.plugin_path
20
+ File.join(PLUGINS_DIR, 'appbox.rb')
21
+ end
22
+
23
+ def self.plugin_destination
24
+ File.join(Dir.pwd, 'plugins', 'appbox.rb')
25
+ end
26
+
27
+ def self.css_path
28
+ File.join(CSS_DIR, 'appbox.css')
29
+ end
30
+
31
+ def self.css_destination
32
+ File.join(Dir.pwd, 'source', 'stylesheets', 'appbox.css')
33
+ end
34
+
35
+ def self.add_stylesheet
36
+ File.open('source/_includes/custom/head.html', 'a') { |file| file << "<link href=\"{{ root_url }}/stylesheets/appbox.css\" media=\"screen, projection\" rel=\"stylesheet\" type=\"text/css\">\n"}
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,140 @@
1
+ .star {
2
+ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAKCAQAAADI+WwIAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAACXZwQWcAAAALAAAACgCF+qVAAAAAhUlEQVQI103NMQqCABgF4C+Fxg7QHDQ0JkFnaKqlKJBu4Np9hEDoBq2doCYP0B4UBKLYUKZvex+P/+9N/dJ3FXl9S9CopbF9U1pOkAgb3irVanOMlGqldeBoo9CmspMFOFmp/hzLmtuXzvrWvpwJFVJvLLqci8Qmzl8OhzBwcMdD6ilXfwAd9B9f78yTCQAAAABJRU5ErkJggg==) no-repeat;
3
+ background-size: 11px 10px;
4
+ }
5
+
6
+ .unstar {
7
+ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAKCAQAAADI+WwIAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAACXZwQWcAAAALAAAACgCF+qVAAAAAo0lEQVQI1z2NMQrCQBRE32YxGFDwBGJnYZkll0ilpDISLO28k4lFwN7CTsTKSisbK8ELCJFI/BZJdn41j/kzSqiVuZ3r1yzeAAanoajpcOwsW2dxf+0yWGe6CaVzNmgY4VHyQKAiVsIlUlvc9otK4lXugNnJjKqlkpi86X6exIZfNztZBGhKUgr4hBZ3A3UX4ye/CYdeWHch7MOzJ9R3jFLt8we7izGyoi32iQAAAABJRU5ErkJggg==) no-repeat;
8
+ background-size: 11px 10px;
9
+ }
10
+ .half-star {
11
+ background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAKCAQAAADI+WwIAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAJdnBBZwAAAAsAAAAKAIX6pUAAAACTSURBVAjXTY0xCsJAEEVfdiEgpPAWFpYTvMRWSioDwdIuh7GydbEIeAM7sU1lo42tR1CEdSzMJk4178H/H7qTVK4+A0URTNTMmZhVhEHXMK69/UEiS3Z0sOGOQqBMQAr2pABbgKDlujHQHlgQYpdWeRO7z/0Cj8swOcPyxvOEl/vXN/K2+kw5Zq4PipNR/E+Ft8IX7yMjsFUGo0cAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzVxteM2AAAAAElFTkSuQmCC) no-repeat;
12
+ background-size: 11px 10px;
13
+ }
14
+ .rating {
15
+ width: 11px;
16
+ height: 10px;
17
+ display: inline-block;
18
+ background-size: 11px 10px
19
+ }
20
+
21
+ .appicon {
22
+ width: 64px;
23
+ height: 64px;
24
+ float: left;
25
+ margin: 10px !important;
26
+ border-radius: 5px;
27
+ -moz-border-radius: 5px;
28
+ -webkit-border-radius: 5px
29
+ }
30
+
31
+ .appbox {
32
+ clear: both;
33
+ font-family: Arial;
34
+ border: 1px solid #E5E5E5;
35
+ background-color: #F9F9F9;
36
+ width: auto;
37
+ line-height: 1;
38
+ color: #545450;
39
+ margin: 16px 0;
40
+ font-size: 1em/16px;
41
+ }
42
+
43
+ .appdetails {
44
+ font-size: .95em;
45
+ margin: 10px;
46
+ height: 64px;
47
+ }
48
+
49
+ .apptitle {
50
+ font-size: 1.15em;
51
+ font-weight: bold;
52
+ height: 22px;
53
+ padding: 0;
54
+ margin: 0;
55
+ }
56
+
57
+ .apptitle a {
58
+ color: #000 !important;
59
+ }
60
+
61
+ .apptitle a:hover {
62
+ text-decoration: none !important;
63
+ color: #B4B4B4 !important;
64
+ }
65
+
66
+ .developer {
67
+ height: 21px;
68
+ line-height: 21px;
69
+ vertical-align: middle;
70
+ padding: 0;
71
+ margin: 0;
72
+ }
73
+
74
+ .price {
75
+ height: 20px;
76
+ display: table-cell;
77
+ vertical-align: bottom;
78
+ padding: 0;
79
+ margin: 0;
80
+ }
81
+
82
+ .screenshots {
83
+ width: auto;
84
+ margin: 0 auto;
85
+ padding: 10px;
86
+ }
87
+
88
+ .screenshots .slider {
89
+ overflow-x: scroll;
90
+ overflow-y: hidden;
91
+ height: 300px;
92
+ margin-top: 0;
93
+ }
94
+
95
+ .screenshots .slider ul {
96
+ padding: 0 !important;
97
+ margin: 0 !important;
98
+ list-style-image: none;
99
+ white-space: nowrap;
100
+ }
101
+
102
+ .screenshots .slider ul li {
103
+ padding: 0;
104
+ margin: 0;
105
+ margin-right: 6px;
106
+ list-style-type: none;
107
+ display: inline;
108
+ }
109
+
110
+ .screenshots .slider ul li:last-child {
111
+ margin-right: 0;
112
+ }
113
+
114
+ .screenshots .slider ul li img {
115
+ height: 300px !important;
116
+ display: inline;
117
+ }
118
+
119
+ .appbutton {
120
+ height: 44px;
121
+ float: right;
122
+ margin: 10px;
123
+ display: inline-block;
124
+ background-color: #E5E5E5;
125
+ border: 1px solid #E5E5E5;
126
+ padding: 10px 15px;
127
+ font-weight: bold;
128
+ font-size: .95em;
129
+ line-height: 1.6em;
130
+ text-align: center;
131
+ border-radius: 5px;
132
+ -moz-border-radius: 5px;
133
+ -webkit-border-radius: 5px;
134
+ }
135
+
136
+ .appbutton:hover {
137
+ background-color: #C1C1C1;
138
+ color: #FFF;
139
+ text-decoration: none !important;
140
+ }
@@ -0,0 +1,182 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'nokogiri'
5
+ require 'open-uri'
6
+ require 'digest/md5'
7
+
8
+ module Jekyll
9
+ class AppBox < Liquid::Tag
10
+
11
+ @id = ''
12
+ @store = ''
13
+ @style = ''
14
+
15
+ def initialize(tag_name, markup, tokens)
16
+ super
17
+ @result = Hash.new
18
+
19
+ @resultarray = ['icon', 'screenshots', 'name', 'url', 'version', 'price', 'developer', 'developerurl','rating']
20
+
21
+ @cachefolder = File.expand_path "../.appboxcache", File.dirname(__FILE__)
22
+ FileUtils.mkdir_p @cachefolder
23
+
24
+ if markup =~ /([A-Za-z]+)(\s[A-Za-z]+\s|\s)([A-Za-z._0-9]+)/i
25
+ @id = $3.strip
26
+ @style = $2.strip
27
+ @store = $1.strip
28
+ else
29
+ puts "Error with Markup. Your Values -- Id: #{@id} -- Style: #{@style} -- Store: #{@store}"
30
+ end
31
+ end
32
+
33
+ def render(context)
34
+ # Get ID of post to generate identifying MD5 hash
35
+ @post_id = context["page"]["id"]
36
+ # make sure to pass only posts with id
37
+ unless @post_id.nil?
38
+ if File.exist? get_cached_file(@store, @id, @post_id)
39
+ get_cached_data(@id)
40
+ else
41
+ if @store == 'appstore'
42
+ apple_fetch_data(@id)
43
+ elsif @store == 'googleplay'
44
+ googleplay_fetch_data(@id)
45
+ end
46
+ end
47
+
48
+ out = ''
49
+ out += get_small_style
50
+
51
+ if @style == 'screenshots'
52
+ out += get_screenshot_style
53
+ end
54
+ out += get_footer
55
+
56
+ %(#{out})
57
+ end
58
+ end
59
+
60
+
61
+ def get_small_style
62
+
63
+ small = ''
64
+ small += "<p><div class=\"appbox\"><a class=\"appbutton\" href=\"#{@result["url"]}\">"
65
+ if @store == 'appstore'
66
+ small += "Go to <br />AppStore"
67
+ elsif @store == 'googleplay'
68
+ small += "Go to <br /> PlayStore"
69
+ end
70
+ small += "</a>"
71
+ small += "<div><a href=\"#{@result["url"]}\">"
72
+ small += "<img class=\"appicon\" src=\"#{@result["icon"]}\" /></a></div>"
73
+ small += "<div class=\"appdetails\"><div class=\"apptitle\"><a href=\"#{@result["url"]}\">#{@result["name"]}</a></div>"
74
+ small += "<div class=\"developer\"><a href=\"#{@result["developerurl"]}\">#{@result["developer"]}</a></div>"
75
+ small += "<div class=\"price\">#{@result["price"]} #{get_rating_stars(@result["rating"])}</div>"
76
+ small += "</div>"
77
+ small
78
+ end
79
+
80
+ def get_footer
81
+ footer = ''
82
+ footer += "</div></p>"
83
+ footer
84
+ end
85
+
86
+ def get_screenshot_style
87
+ screenshots = ''
88
+
89
+ screenshots += "<div class=\"screenshots\"><div class=\"slider\"><ul>"
90
+ unless @result["screenshots"].empty?
91
+ @result["screenshots"].each do |screenshot|
92
+ screenshots += "<li><img src=\"#{screenshot}\" /></li>"
93
+ end
94
+ end
95
+ screenshots += "</ul></div></div>"
96
+ screenshots
97
+ end
98
+
99
+ def get_rating_stars(value)
100
+ stars = ''
101
+ value.to_i.times do |star|
102
+ stars += "<span class=\"rating star\"></span>"
103
+ end
104
+ unless value.modulo(1) < 0.5
105
+ stars += "<span class=\"rating half-star\"></span>"
106
+ end
107
+ halfstar = 0
108
+ halfstar = 1 if value.modulo(1) >= 0.5
109
+ (5 - value.to_i - halfstar).times do |emptystar|
110
+ stars += "<span class=\"rating unstar\"></span>"
111
+ end
112
+ stars
113
+ end
114
+
115
+ def apple_fetch_data(app_id)
116
+ requestarray = ['artworkUrl512','screenshotUrls','trackName','trackViewUrl','version','formattedPrice','artistName','artistViewUrl', 'averageUserRatingForCurrentVersion']
117
+
118
+ url = "http://itunes.apple.com/lookup?id=#{app_id}"
119
+ resp = Net::HTTP.get_response(URI.parse(url))
120
+ app_data = JSON.parse resp.body
121
+
122
+ @resultarray.zip(requestarray).each do |result,request|
123
+ @result[result] = app_data["results"][0][request]
124
+ end
125
+
126
+ save_cached_data(get_cached_file(@store, app_id, @post_id))
127
+ end
128
+
129
+ def googleplay_fetch_data(app_id)
130
+ base_url = 'https://play.google.com'
131
+
132
+ doc = Nokogiri::HTML(open("#{base_url}/store/apps/details?id=#{app_id}"), nil, 'utf-8')
133
+
134
+ # requestarray hints:
135
+ # 1) App Icon e.g. big icon in Chrome Webstore
136
+ # 2) Array of screenshots
137
+ # 3) Name of the app
138
+ # 4) URL to the app
139
+ # 5) Versionnumber of the app
140
+ # 6) Price of the app
141
+ # 7) Developername
142
+ # 8) Developer URL
143
+ # 9) Rating value
144
+
145
+ requestarray = [ doc.css("div.cover-container img").first['src'],
146
+ doc.css("div.thumbnails img.screenshot").collect {|thumb| thumb['src']},
147
+ doc.css("div.info-container div.document-title div").first.content,
148
+ base_url + "/store/apps/details?id=#{app_id}",
149
+ doc.css("div[itemprop=softwareVersion]").first.content.strip,
150
+ doc.css("meta[itemprop=price]").first['content'],
151
+ doc.css("div.info-container div a.document-subtitle").first.content,
152
+ base_url + doc.css("div.info-container div a.document-subtitle").first['href'],
153
+ doc.css("div.tiny-star div.current-rating").first['style'][/\d+\.\d+/].to_f.round(1) / 100 * 5
154
+ ]
155
+ @resultarray.zip(requestarray).each do |result, request|
156
+ @result[result] = request
157
+ end
158
+
159
+ save_cached_data(get_cached_file(@store, app_id, @post_id))
160
+ end
161
+
162
+ def get_cached_data(app_id)
163
+ cached_file = get_cached_file(@store, app_id, @post_id)
164
+ @result = JSON.parse File.read cached_file if File.exist? cached_file
165
+ return nil if @result.nil?
166
+ end
167
+
168
+ def save_cached_data(cached_file)
169
+ File.open(cached_file, "w") do |file|
170
+ file.write @result.to_json
171
+ end
172
+ end
173
+
174
+ def get_cached_file(store, app_id, post_id)
175
+ File.join @cachefolder, "#{store}_#{app_id}-#{Digest::MD5.hexdigest(post_id)}.cache"
176
+ end
177
+
178
+ end
179
+ end
180
+
181
+ Liquid::Template.register_tag('appbox', Jekyll::AppBox)
182
+
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appbox-octopress
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Philipp Jaeckel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Parse and visualize data from AppStore and GooglePlay Store to display
14
+ it in Octopress or Jekyll posts
15
+ email: mail@sots.name
16
+ executables:
17
+ - appbox-octopress
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/appbox_octopress/utilities.rb
22
+ - lib/appbox_octopress.rb
23
+ - bin/appbox-octopress
24
+ - templates/css/appbox.css
25
+ - templates/plugins/appbox.rb
26
+ homepage: http://rubygems.org/gems/appbox-octopress
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.1.10
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: AppBox Octopress
50
+ test_files: []