rsteamshot 0.1.1
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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +118 -0
- data/Rakefile +14 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/README_md.html +233 -0
- data/docs/Rsteamshot/App/BadAppsFile.html +106 -0
- data/docs/Rsteamshot/App.html +466 -0
- data/docs/Rsteamshot/Screenshot.html +562 -0
- data/docs/Rsteamshot/ScreenshotPage.html +347 -0
- data/docs/Rsteamshot/ScreenshotPaginator.html +307 -0
- data/docs/Rsteamshot/User.html +309 -0
- data/docs/Rsteamshot.html +147 -0
- data/docs/created.rid +9 -0
- data/docs/css/fonts.css +167 -0
- data/docs/css/rdoc.css +590 -0
- data/docs/fonts/Lato-Light.ttf +0 -0
- data/docs/fonts/Lato-LightItalic.ttf +0 -0
- data/docs/fonts/Lato-Regular.ttf +0 -0
- data/docs/fonts/Lato-RegularItalic.ttf +0 -0
- data/docs/fonts/SourceCodePro-Bold.ttf +0 -0
- data/docs/fonts/SourceCodePro-Regular.ttf +0 -0
- data/docs/images/add.png +0 -0
- data/docs/images/arrow_up.png +0 -0
- data/docs/images/brick.png +0 -0
- data/docs/images/brick_link.png +0 -0
- data/docs/images/bug.png +0 -0
- data/docs/images/bullet_black.png +0 -0
- data/docs/images/bullet_toggle_minus.png +0 -0
- data/docs/images/bullet_toggle_plus.png +0 -0
- data/docs/images/date.png +0 -0
- data/docs/images/delete.png +0 -0
- data/docs/images/find.png +0 -0
- data/docs/images/loadingAnimation.gif +0 -0
- data/docs/images/macFFBgHack.png +0 -0
- data/docs/images/package.png +0 -0
- data/docs/images/page_green.png +0 -0
- data/docs/images/page_white_text.png +0 -0
- data/docs/images/page_white_width.png +0 -0
- data/docs/images/plugin.png +0 -0
- data/docs/images/ruby.png +0 -0
- data/docs/images/tag_blue.png +0 -0
- data/docs/images/tag_green.png +0 -0
- data/docs/images/transparent.png +0 -0
- data/docs/images/wrench.png +0 -0
- data/docs/images/wrench_orange.png +0 -0
- data/docs/images/zoom.png +0 -0
- data/docs/index.html +242 -0
- data/docs/js/darkfish.js +161 -0
- data/docs/js/jquery.js +4 -0
- data/docs/js/navigation.js +142 -0
- data/docs/js/navigation.js.gz +0 -0
- data/docs/js/search.js +109 -0
- data/docs/js/search_index.js +1 -0
- data/docs/js/search_index.js.gz +0 -0
- data/docs/js/searcher.js +229 -0
- data/docs/js/searcher.js.gz +0 -0
- data/docs/table_of_contents.html +179 -0
- data/lib/rsteamshot/app.rb +213 -0
- data/lib/rsteamshot/screenshot.rb +224 -0
- data/lib/rsteamshot/screenshot_page.rb +62 -0
- data/lib/rsteamshot/screenshot_paginator.rb +77 -0
- data/lib/rsteamshot/user.rb +77 -0
- data/lib/rsteamshot/version.rb +4 -0
- data/lib/rsteamshot.rb +15 -0
- data/rsteamshot.gemspec +32 -0
- metadata +215 -0
data/docs/js/searcher.js
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
Searcher = function(data) {
|
2
|
+
this.data = data;
|
3
|
+
this.handlers = [];
|
4
|
+
}
|
5
|
+
|
6
|
+
Searcher.prototype = new function() {
|
7
|
+
// search is performed in chunks of 1000 for non-blocking user input
|
8
|
+
var CHUNK_SIZE = 1000;
|
9
|
+
// do not try to find more than 100 results
|
10
|
+
var MAX_RESULTS = 100;
|
11
|
+
var huid = 1;
|
12
|
+
var suid = 1;
|
13
|
+
var runs = 0;
|
14
|
+
|
15
|
+
this.find = function(query) {
|
16
|
+
var queries = splitQuery(query);
|
17
|
+
var regexps = buildRegexps(queries);
|
18
|
+
var highlighters = buildHilighters(queries);
|
19
|
+
var state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++};
|
20
|
+
var _this = this;
|
21
|
+
|
22
|
+
this.currentSuid = state.n;
|
23
|
+
|
24
|
+
if (!query) return;
|
25
|
+
|
26
|
+
var run = function() {
|
27
|
+
// stop current search thread if new search started
|
28
|
+
if (state.n != _this.currentSuid) return;
|
29
|
+
|
30
|
+
var results =
|
31
|
+
performSearch(_this.data, regexps, queries, highlighters, state);
|
32
|
+
var hasMore = (state.limit > 0 && state.pass < 4);
|
33
|
+
|
34
|
+
triggerResults.call(_this, results, !hasMore);
|
35
|
+
if (hasMore) {
|
36
|
+
setTimeout(run, 2);
|
37
|
+
}
|
38
|
+
runs++;
|
39
|
+
};
|
40
|
+
runs = 0;
|
41
|
+
|
42
|
+
// start search thread
|
43
|
+
run();
|
44
|
+
}
|
45
|
+
|
46
|
+
/* ----- Events ------ */
|
47
|
+
this.ready = function(fn) {
|
48
|
+
fn.huid = huid;
|
49
|
+
this.handlers.push(fn);
|
50
|
+
}
|
51
|
+
|
52
|
+
/* ----- Utilities ------ */
|
53
|
+
function splitQuery(query) {
|
54
|
+
return jQuery.grep(query.split(/(\s+|::?|\(\)?)/), function(string) {
|
55
|
+
return string.match(/\S/);
|
56
|
+
});
|
57
|
+
}
|
58
|
+
|
59
|
+
function buildRegexps(queries) {
|
60
|
+
return jQuery.map(queries, function(query) {
|
61
|
+
return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i');
|
62
|
+
});
|
63
|
+
}
|
64
|
+
|
65
|
+
function buildHilighters(queries) {
|
66
|
+
return jQuery.map(queries, function(query) {
|
67
|
+
return jQuery.map(query.split(''), function(l, i) {
|
68
|
+
return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2);
|
69
|
+
}).join('');
|
70
|
+
});
|
71
|
+
}
|
72
|
+
|
73
|
+
// function longMatchRegexp(index, longIndex, regexps) {
|
74
|
+
// for (var i = regexps.length - 1; i >= 0; i--){
|
75
|
+
// if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
|
76
|
+
// };
|
77
|
+
// return true;
|
78
|
+
// }
|
79
|
+
|
80
|
+
|
81
|
+
/* ----- Mathchers ------ */
|
82
|
+
|
83
|
+
/*
|
84
|
+
* This record matches if the index starts with queries[0] and the record
|
85
|
+
* matches all of the regexps
|
86
|
+
*/
|
87
|
+
function matchPassBeginning(index, longIndex, queries, regexps) {
|
88
|
+
if (index.indexOf(queries[0]) != 0) return false;
|
89
|
+
for (var i=1, l = regexps.length; i < l; i++) {
|
90
|
+
if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
|
91
|
+
return false;
|
92
|
+
};
|
93
|
+
return true;
|
94
|
+
}
|
95
|
+
|
96
|
+
/*
|
97
|
+
* This record matches if the longIndex starts with queries[0] and the
|
98
|
+
* longIndex matches all of the regexps
|
99
|
+
*/
|
100
|
+
function matchPassLongIndex(index, longIndex, queries, regexps) {
|
101
|
+
if (longIndex.indexOf(queries[0]) != 0) return false;
|
102
|
+
for (var i=1, l = regexps.length; i < l; i++) {
|
103
|
+
if (!longIndex.match(regexps[i]))
|
104
|
+
return false;
|
105
|
+
};
|
106
|
+
return true;
|
107
|
+
}
|
108
|
+
|
109
|
+
/*
|
110
|
+
* This record matches if the index contains queries[0] and the record
|
111
|
+
* matches all of the regexps
|
112
|
+
*/
|
113
|
+
function matchPassContains(index, longIndex, queries, regexps) {
|
114
|
+
if (index.indexOf(queries[0]) == -1) return false;
|
115
|
+
for (var i=1, l = regexps.length; i < l; i++) {
|
116
|
+
if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
|
117
|
+
return false;
|
118
|
+
};
|
119
|
+
return true;
|
120
|
+
}
|
121
|
+
|
122
|
+
/*
|
123
|
+
* This record matches if regexps[0] matches the index and the record
|
124
|
+
* matches all of the regexps
|
125
|
+
*/
|
126
|
+
function matchPassRegexp(index, longIndex, queries, regexps) {
|
127
|
+
if (!index.match(regexps[0])) return false;
|
128
|
+
for (var i=1, l = regexps.length; i < l; i++) {
|
129
|
+
if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
|
130
|
+
return false;
|
131
|
+
};
|
132
|
+
return true;
|
133
|
+
}
|
134
|
+
|
135
|
+
|
136
|
+
/* ----- Highlighters ------ */
|
137
|
+
function highlightRegexp(info, queries, regexps, highlighters) {
|
138
|
+
var result = createResult(info);
|
139
|
+
for (var i=0, l = regexps.length; i < l; i++) {
|
140
|
+
result.title = result.title.replace(regexps[i], highlighters[i]);
|
141
|
+
result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
|
142
|
+
};
|
143
|
+
return result;
|
144
|
+
}
|
145
|
+
|
146
|
+
function hltSubstring(string, pos, length) {
|
147
|
+
return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length);
|
148
|
+
}
|
149
|
+
|
150
|
+
function highlightQuery(info, queries, regexps, highlighters) {
|
151
|
+
var result = createResult(info);
|
152
|
+
var pos = 0;
|
153
|
+
var lcTitle = result.title.toLowerCase();
|
154
|
+
|
155
|
+
pos = lcTitle.indexOf(queries[0]);
|
156
|
+
if (pos != -1) {
|
157
|
+
result.title = hltSubstring(result.title, pos, queries[0].length);
|
158
|
+
}
|
159
|
+
|
160
|
+
result.namespace = result.namespace.replace(regexps[0], highlighters[0]);
|
161
|
+
for (var i=1, l = regexps.length; i < l; i++) {
|
162
|
+
result.title = result.title.replace(regexps[i], highlighters[i]);
|
163
|
+
result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
|
164
|
+
};
|
165
|
+
return result;
|
166
|
+
}
|
167
|
+
|
168
|
+
function createResult(info) {
|
169
|
+
var result = {};
|
170
|
+
result.title = info[0];
|
171
|
+
result.namespace = info[1];
|
172
|
+
result.path = info[2];
|
173
|
+
result.params = info[3];
|
174
|
+
result.snippet = info[4];
|
175
|
+
result.badge = info[6];
|
176
|
+
return result;
|
177
|
+
}
|
178
|
+
|
179
|
+
/* ----- Searching ------ */
|
180
|
+
function performSearch(data, regexps, queries, highlighters, state) {
|
181
|
+
var searchIndex = data.searchIndex;
|
182
|
+
var longSearchIndex = data.longSearchIndex;
|
183
|
+
var info = data.info;
|
184
|
+
var result = [];
|
185
|
+
var i = state.from;
|
186
|
+
var l = searchIndex.length;
|
187
|
+
var togo = CHUNK_SIZE;
|
188
|
+
var matchFunc, hltFunc;
|
189
|
+
|
190
|
+
while (state.pass < 4 && state.limit > 0 && togo > 0) {
|
191
|
+
if (state.pass == 0) {
|
192
|
+
matchFunc = matchPassBeginning;
|
193
|
+
hltFunc = highlightQuery;
|
194
|
+
} else if (state.pass == 1) {
|
195
|
+
matchFunc = matchPassLongIndex;
|
196
|
+
hltFunc = highlightQuery;
|
197
|
+
} else if (state.pass == 2) {
|
198
|
+
matchFunc = matchPassContains;
|
199
|
+
hltFunc = highlightQuery;
|
200
|
+
} else if (state.pass == 3) {
|
201
|
+
matchFunc = matchPassRegexp;
|
202
|
+
hltFunc = highlightRegexp;
|
203
|
+
}
|
204
|
+
|
205
|
+
for (; togo > 0 && i < l && state.limit > 0; i++, togo--) {
|
206
|
+
if (info[i].n == state.n) continue;
|
207
|
+
if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) {
|
208
|
+
info[i].n = state.n;
|
209
|
+
result.push(hltFunc(info[i], queries, regexps, highlighters));
|
210
|
+
state.limit--;
|
211
|
+
}
|
212
|
+
};
|
213
|
+
if (searchIndex.length <= i) {
|
214
|
+
state.pass++;
|
215
|
+
i = state.from = 0;
|
216
|
+
} else {
|
217
|
+
state.from = i;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
return result;
|
221
|
+
}
|
222
|
+
|
223
|
+
function triggerResults(results, isLast) {
|
224
|
+
jQuery.each(this.handlers, function(i, fn) {
|
225
|
+
fn.call(this, results, isLast)
|
226
|
+
})
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
Binary file
|
@@ -0,0 +1,179 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
|
7
|
+
<title>Table of Contents - RDoc Documentation</title>
|
8
|
+
|
9
|
+
<script type="text/javascript">
|
10
|
+
var rdoc_rel_prefix = "./";
|
11
|
+
var index_rel_prefix = "./";
|
12
|
+
</script>
|
13
|
+
|
14
|
+
<script src="./js/jquery.js"></script>
|
15
|
+
<script src="./js/darkfish.js"></script>
|
16
|
+
|
17
|
+
<link href="./css/fonts.css" rel="stylesheet">
|
18
|
+
<link href="./css/rdoc.css" rel="stylesheet">
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
<body id="top" class="table-of-contents">
|
23
|
+
<main role="main">
|
24
|
+
<h1 class="class">Table of Contents - RDoc Documentation</h1>
|
25
|
+
|
26
|
+
<h2 id="pages">Pages</h2>
|
27
|
+
<ul>
|
28
|
+
<li class="file">
|
29
|
+
<a href="README_md.html">README</a>
|
30
|
+
|
31
|
+
<ul>
|
32
|
+
<li><a href="README_md.html#label-Rsteamshot">Rsteamshot</a>
|
33
|
+
<li><a href="README_md.html#label-Installation">Installation</a>
|
34
|
+
<li><a href="README_md.html#label-Usage">Usage</a>
|
35
|
+
<li><a href="README_md.html#label-Development">Development</a>
|
36
|
+
<li><a href="README_md.html#label-Contributing">Contributing</a>
|
37
|
+
<li><a href="README_md.html#label-License">License</a>
|
38
|
+
</ul>
|
39
|
+
</li>
|
40
|
+
|
41
|
+
</ul>
|
42
|
+
|
43
|
+
<h2 id="classes">Classes and Modules</h2>
|
44
|
+
<ul>
|
45
|
+
<li class="module">
|
46
|
+
<a href="Rsteamshot.html">Rsteamshot</a>
|
47
|
+
</li>
|
48
|
+
<li class="class">
|
49
|
+
<a href="Rsteamshot/App.html">Rsteamshot::App</a>
|
50
|
+
|
51
|
+
<ul>
|
52
|
+
<li><a href="Rsteamshot/App.html#Public">Public</a>
|
53
|
+
</ul>
|
54
|
+
</li>
|
55
|
+
<li class="class">
|
56
|
+
<a href="Rsteamshot/App/BadAppsFile.html">Rsteamshot::App::BadAppsFile</a>
|
57
|
+
</li>
|
58
|
+
<li class="class">
|
59
|
+
<a href="Rsteamshot/Screenshot.html">Rsteamshot::Screenshot</a>
|
60
|
+
|
61
|
+
<ul>
|
62
|
+
<li><a href="Rsteamshot/Screenshot.html#Public">Public</a>
|
63
|
+
</ul>
|
64
|
+
</li>
|
65
|
+
<li class="class">
|
66
|
+
<a href="Rsteamshot/ScreenshotPage.html">Rsteamshot::ScreenshotPage</a>
|
67
|
+
|
68
|
+
<ul>
|
69
|
+
<li><a href="Rsteamshot/ScreenshotPage.html#Public">Public</a>
|
70
|
+
</ul>
|
71
|
+
</li>
|
72
|
+
<li class="class">
|
73
|
+
<a href="Rsteamshot/ScreenshotPaginator.html">Rsteamshot::ScreenshotPaginator</a>
|
74
|
+
|
75
|
+
<ul>
|
76
|
+
<li><a href="Rsteamshot/ScreenshotPaginator.html#Public">Public</a>
|
77
|
+
</ul>
|
78
|
+
</li>
|
79
|
+
<li class="class">
|
80
|
+
<a href="Rsteamshot/User.html">Rsteamshot::User</a>
|
81
|
+
|
82
|
+
<ul>
|
83
|
+
<li><a href="Rsteamshot/User.html#Public">Public</a>
|
84
|
+
</ul>
|
85
|
+
</li>
|
86
|
+
</ul>
|
87
|
+
|
88
|
+
<h2 id="methods">Methods</h2>
|
89
|
+
<ul>
|
90
|
+
|
91
|
+
<li class="method">
|
92
|
+
<a href="Rsteamshot/App.html#method-c-download_apps_list">::download_apps_list</a>
|
93
|
+
—
|
94
|
+
<span class="container">Rsteamshot::App</span>
|
95
|
+
|
96
|
+
<li class="method">
|
97
|
+
<a href="Rsteamshot/App.html#method-c-new">::new</a>
|
98
|
+
—
|
99
|
+
<span class="container">Rsteamshot::App</span>
|
100
|
+
|
101
|
+
<li class="method">
|
102
|
+
<a href="Rsteamshot/ScreenshotPage.html#method-c-new">::new</a>
|
103
|
+
—
|
104
|
+
<span class="container">Rsteamshot::ScreenshotPage</span>
|
105
|
+
|
106
|
+
<li class="method">
|
107
|
+
<a href="Rsteamshot/Screenshot.html#method-c-new">::new</a>
|
108
|
+
—
|
109
|
+
<span class="container">Rsteamshot::Screenshot</span>
|
110
|
+
|
111
|
+
<li class="method">
|
112
|
+
<a href="Rsteamshot/ScreenshotPaginator.html#method-c-new">::new</a>
|
113
|
+
—
|
114
|
+
<span class="container">Rsteamshot::ScreenshotPaginator</span>
|
115
|
+
|
116
|
+
<li class="method">
|
117
|
+
<a href="Rsteamshot/User.html#method-c-new">::new</a>
|
118
|
+
—
|
119
|
+
<span class="container">Rsteamshot::User</span>
|
120
|
+
|
121
|
+
<li class="method">
|
122
|
+
<a href="Rsteamshot/App.html#method-c-search">::search</a>
|
123
|
+
—
|
124
|
+
<span class="container">Rsteamshot::App</span>
|
125
|
+
|
126
|
+
<li class="method">
|
127
|
+
<a href="Rsteamshot/ScreenshotPage.html#method-i-fetch">#fetch</a>
|
128
|
+
—
|
129
|
+
<span class="container">Rsteamshot::ScreenshotPage</span>
|
130
|
+
|
131
|
+
<li class="method">
|
132
|
+
<a href="Rsteamshot/ScreenshotPage.html#method-i-includes_screenshot-3F">#includes_screenshot?</a>
|
133
|
+
—
|
134
|
+
<span class="container">Rsteamshot::ScreenshotPage</span>
|
135
|
+
|
136
|
+
<li class="method">
|
137
|
+
<a href="Rsteamshot/Screenshot.html#method-i-inspect">#inspect</a>
|
138
|
+
—
|
139
|
+
<span class="container">Rsteamshot::Screenshot</span>
|
140
|
+
|
141
|
+
<li class="method">
|
142
|
+
<a href="Rsteamshot/ScreenshotPaginator.html#method-i-per_page">#per_page</a>
|
143
|
+
—
|
144
|
+
<span class="container">Rsteamshot::ScreenshotPaginator</span>
|
145
|
+
|
146
|
+
<li class="method">
|
147
|
+
<a href="Rsteamshot/ScreenshotPaginator.html#method-i-screenshots">#screenshots</a>
|
148
|
+
—
|
149
|
+
<span class="container">Rsteamshot::ScreenshotPaginator</span>
|
150
|
+
|
151
|
+
<li class="method">
|
152
|
+
<a href="Rsteamshot/User.html#method-i-screenshots">#screenshots</a>
|
153
|
+
—
|
154
|
+
<span class="container">Rsteamshot::User</span>
|
155
|
+
|
156
|
+
<li class="method">
|
157
|
+
<a href="Rsteamshot/App.html#method-i-screenshots">#screenshots</a>
|
158
|
+
—
|
159
|
+
<span class="container">Rsteamshot::App</span>
|
160
|
+
|
161
|
+
<li class="method">
|
162
|
+
<a href="Rsteamshot/Screenshot.html#method-i-to_h">#to_h</a>
|
163
|
+
—
|
164
|
+
<span class="container">Rsteamshot::Screenshot</span>
|
165
|
+
|
166
|
+
<li class="method">
|
167
|
+
<a href="Rsteamshot/Screenshot.html#method-i-to_json">#to_json</a>
|
168
|
+
—
|
169
|
+
<span class="container">Rsteamshot::Screenshot</span>
|
170
|
+
</ul>
|
171
|
+
</main>
|
172
|
+
|
173
|
+
|
174
|
+
<footer id="validator-badges" role="contentinfo">
|
175
|
+
<p><a href="http://validator.w3.org/check/referer">Validate</a>
|
176
|
+
<p>Generated by <a href="https://rdoc.github.io/rdoc">RDoc</a> 5.1.0.
|
177
|
+
<p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
|
178
|
+
</footer>
|
179
|
+
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module Rsteamshot
|
2
|
+
# Public: Represents a Steam app, like a video game. Used to fetch the screenshots
|
3
|
+
# that were taken in that app that Steam users have uploaded.
|
4
|
+
class App
|
5
|
+
# Public: Exception thrown by Rsteamshot::App#search when the given file is not a valid file
|
6
|
+
# containing Steam apps.
|
7
|
+
class BadAppsFile < StandardError; end
|
8
|
+
|
9
|
+
# Public: You can fetch this many screenshots at once.
|
10
|
+
MAX_PER_PAGE = 50
|
11
|
+
|
12
|
+
# Public: The API URL to get a list of apps on Steam.
|
13
|
+
APPS_LIST_URL = 'http://api.steampowered.com/ISteamApps/GetAppList/v2'
|
14
|
+
|
15
|
+
# Public: How to sort screenshots when they are being retrieved.
|
16
|
+
VALID_ORDERS = %w[mostrecent toprated trendday trendweek trendthreemonths
|
17
|
+
trendsixmonths trendyear].freeze
|
18
|
+
|
19
|
+
# Public: Returns the ID of the Steam app as an Integer or String.
|
20
|
+
attr_reader :id
|
21
|
+
|
22
|
+
# Public: Returns the String name of the Steam app, or nil.
|
23
|
+
attr_reader :name
|
24
|
+
|
25
|
+
# Public: Writes a JSON file at the given location with the latest list of apps on Steam.
|
26
|
+
#
|
27
|
+
# path - a String file path
|
28
|
+
#
|
29
|
+
# Returns nothing.
|
30
|
+
def self.download_apps_list(path)
|
31
|
+
File.open(path, 'w') do |file|
|
32
|
+
IO.copy_stream(open(APPS_LIST_URL), file)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Find Steam apps by name.
|
37
|
+
#
|
38
|
+
# raw_query - a String search query for an app or game on Steam
|
39
|
+
# apps_list_path - a String file path to the JSON file produced by #download_apps_list
|
40
|
+
#
|
41
|
+
# Returns an Array of Rsteamshot::Apps.
|
42
|
+
def self.search(raw_query, apps_list_path)
|
43
|
+
return [] unless raw_query
|
44
|
+
|
45
|
+
unless apps_list_path
|
46
|
+
raise BadAppsFile, 'no path given to JSON apps list from Steam'
|
47
|
+
end
|
48
|
+
|
49
|
+
unless File.file?(apps_list_path)
|
50
|
+
raise BadAppsFile, "#{apps_list_path} is not a file"
|
51
|
+
end
|
52
|
+
|
53
|
+
json = begin
|
54
|
+
JSON.parse(File.read(apps_list_path))
|
55
|
+
rescue JSON::ParserError
|
56
|
+
raise BadAppsFile, "#{apps_list_path} is not a valid JSON file"
|
57
|
+
end
|
58
|
+
|
59
|
+
applist = json['applist']
|
60
|
+
unless applist
|
61
|
+
raise BadAppsFile, "#{apps_list_path} does not have expected JSON format"
|
62
|
+
end
|
63
|
+
|
64
|
+
apps = applist['apps']
|
65
|
+
unless apps
|
66
|
+
raise BadAppsFile, "#{apps_list_path} does not have expected JSON format"
|
67
|
+
end
|
68
|
+
|
69
|
+
query = raw_query.downcase
|
70
|
+
results = []
|
71
|
+
apps.each do |data|
|
72
|
+
next unless data['name']
|
73
|
+
|
74
|
+
if data['name'].downcase.include?(query)
|
75
|
+
results << new(id: data['appid'], name: data['name'])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
results
|
80
|
+
end
|
81
|
+
|
82
|
+
# Public: Initialize a Steam app with the given attributes.
|
83
|
+
#
|
84
|
+
# attrs - the Hash of attributes for this app
|
85
|
+
# :id - the String or Integer app ID
|
86
|
+
# :name - the String name of the app
|
87
|
+
# :per_page - how many results to get in each page; defaults to 10; valid range: 1-50;
|
88
|
+
# Integer
|
89
|
+
def initialize(attrs = {})
|
90
|
+
per_page = attrs.delete(:per_page)
|
91
|
+
|
92
|
+
attrs.each { |key, value| instance_variable_set("@#{key}", value) }
|
93
|
+
|
94
|
+
process_html = ->(html) do
|
95
|
+
cards_from(html).map { |card| screenshot_from(card) }
|
96
|
+
end
|
97
|
+
@paginator = ScreenshotPaginator.new(process_html, max_per_page: MAX_PER_PAGE,
|
98
|
+
per_page: per_page, steam_per_page: per_page)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Public: Fetch a list of the newest uploaded screenshots for this app on Steam.
|
102
|
+
#
|
103
|
+
# order - String specifying which screenshots should be retrieved; choose from mostrecent,
|
104
|
+
# toprated, trendday, trendweek, trendthreemonths, trendsixmonths, and trendyear;
|
105
|
+
# defaults to mostrecent
|
106
|
+
# page - which page of results to fetch; defaults to 1; Integer
|
107
|
+
# query - a String of text for searching screenshots
|
108
|
+
#
|
109
|
+
# Returns an Array of Rsteamshot::Screenshots.
|
110
|
+
def screenshots(order: nil, page: 1, query: nil)
|
111
|
+
return [] unless id
|
112
|
+
|
113
|
+
url = steam_url(order, query, @paginator.per_page)
|
114
|
+
@paginator.screenshots(page: page, url: url)
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def cards_from(html)
|
120
|
+
html.search('.apphub_Card')
|
121
|
+
end
|
122
|
+
|
123
|
+
def screenshot_from(card)
|
124
|
+
details_url = card['data-modal-content-url']
|
125
|
+
medium_url, full_size_url = urls_from(card)
|
126
|
+
title = title_from(card)
|
127
|
+
user_link = user_link_from(card)
|
128
|
+
user_name = if user_link
|
129
|
+
user_link.text.strip.gsub(/[[:space:]]\z/, '')
|
130
|
+
end
|
131
|
+
user_url = if user_link
|
132
|
+
user_link['href']
|
133
|
+
end
|
134
|
+
like_count = like_count_from(card)
|
135
|
+
comment_count = comment_count_from(card)
|
136
|
+
Screenshot.new(details_url: details_url, title: title, medium_url: medium_url,
|
137
|
+
full_size_url: full_size_url, user_name: user_name,
|
138
|
+
user_url: user_url, like_count: like_count, comment_count: comment_count)
|
139
|
+
end
|
140
|
+
|
141
|
+
def urls_from(card)
|
142
|
+
image = card.at('.apphub_CardContentPreviewImage')
|
143
|
+
return unless image
|
144
|
+
|
145
|
+
medium_url = image['src']
|
146
|
+
uri = URI.parse(medium_url)
|
147
|
+
full_size_url = "#{uri.scheme}://#{uri.host}#{uri.path}"
|
148
|
+
|
149
|
+
[medium_url, full_size_url]
|
150
|
+
end
|
151
|
+
|
152
|
+
def like_count_from(card)
|
153
|
+
card_rating = card.at('.apphub_CardRating')
|
154
|
+
return 0 unless card_rating
|
155
|
+
|
156
|
+
text = card_rating.text.strip.gsub(/[[:space:]]\z/, '')
|
157
|
+
if text.length > 0
|
158
|
+
text.to_i
|
159
|
+
else
|
160
|
+
0
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def comment_count_from(card)
|
165
|
+
comments_el = card.at('.apphub_CardCommentCount')
|
166
|
+
return 0 unless comments_el
|
167
|
+
|
168
|
+
text = comments_el.text.strip.gsub(/[[:space:]]\z/, '')
|
169
|
+
if text.length > 0
|
170
|
+
text.to_i
|
171
|
+
else
|
172
|
+
0
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def full_size_url_from(medium_url)
|
177
|
+
if medium_url =~ /\.resizedimage$/
|
178
|
+
size_part = medium_url.split('/').last # e.g., 640x359.resizedimage
|
179
|
+
medium_url.split(size_part).first
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def user_link_from(card)
|
184
|
+
links = card.search('.apphub_CardContentAuthorBlock .apphub_CardContentAuthorName a')
|
185
|
+
links.last
|
186
|
+
end
|
187
|
+
|
188
|
+
def title_from(card)
|
189
|
+
title_el = card.at('.apphub_CardMetaData .apphub_CardContentTitle')
|
190
|
+
return unless title_el
|
191
|
+
|
192
|
+
title = title_el.text.strip.gsub(/[[:space:]]\z/, '')
|
193
|
+
title if title.length > 0
|
194
|
+
end
|
195
|
+
|
196
|
+
def steam_url(order, query, per_page)
|
197
|
+
params = [
|
198
|
+
"browsefilter=#{browsefilter_param(order)}",
|
199
|
+
"numperpage=#{per_page}"
|
200
|
+
]
|
201
|
+
params << "searchText=#{URI.escape(query)}" if query
|
202
|
+
"http://steamcommunity.com/app/#{id}/screenshots/?" + params.join('&')
|
203
|
+
end
|
204
|
+
|
205
|
+
def browsefilter_param(order)
|
206
|
+
if VALID_ORDERS.include?(order)
|
207
|
+
order
|
208
|
+
else
|
209
|
+
VALID_ORDERS.first
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|