Spaces:
Build error
Build error
David Li commited on
Commit ·
02ec2cc
1
Parent(s): 46951bb
fix: update dart off server
Browse files- bin/dart_off_server.dart +7 -3
- lib/core.dart +51 -0
- lib/types.dart +28 -0
- pubspec.lock +22 -1
- pubspec.yaml +2 -0
- test/core_test.dart +17 -0
- test/sample.html +0 -0
bin/dart_off_server.dart
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import 'package:dart_off_server/core.dart' as
|
| 2 |
import 'package:alfred/alfred.dart';
|
| 3 |
import 'dart:io';
|
| 4 |
import 'package:openfoodfacts/openfoodfacts.dart';
|
|
@@ -11,7 +11,7 @@ void main(List<String> arguments) async {
|
|
| 11 |
} else {
|
| 12 |
port = int.tryParse(arguments.first) ?? 6565;
|
| 13 |
}
|
| 14 |
-
|
| 15 |
final app = Alfred();
|
| 16 |
|
| 17 |
// print line
|
|
@@ -42,12 +42,16 @@ void main(List<String> arguments) async {
|
|
| 42 |
|
| 43 |
app.get('/food/search', (req, res) {
|
| 44 |
final query = req.uri.queryParameters;
|
| 45 |
-
return
|
| 46 |
res.json(value);
|
| 47 |
}).catchError((error) {
|
| 48 |
res.json(error);
|
| 49 |
});
|
| 50 |
});
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
await app.listen(port); //Listening on port 6565
|
| 53 |
}
|
|
|
|
| 1 |
+
import 'package:dart_off_server/core.dart' as core;
|
| 2 |
import 'package:alfred/alfred.dart';
|
| 3 |
import 'dart:io';
|
| 4 |
import 'package:openfoodfacts/openfoodfacts.dart';
|
|
|
|
| 11 |
} else {
|
| 12 |
port = int.tryParse(arguments.first) ?? 6565;
|
| 13 |
}
|
| 14 |
+
core.mkConfiguration();
|
| 15 |
final app = Alfred();
|
| 16 |
|
| 17 |
// print line
|
|
|
|
| 42 |
|
| 43 |
app.get('/food/search', (req, res) {
|
| 44 |
final query = req.uri.queryParameters;
|
| 45 |
+
return core.search(query).then((value) {
|
| 46 |
res.json(value);
|
| 47 |
}).catchError((error) {
|
| 48 |
res.json(error);
|
| 49 |
});
|
| 50 |
});
|
| 51 |
|
| 52 |
+
app.get('/steam', (req, res) {
|
| 53 |
+
return core.findTopSteamSellers();
|
| 54 |
+
});
|
| 55 |
+
|
| 56 |
await app.listen(port); //Listening on port 6565
|
| 57 |
}
|
lib/core.dart
CHANGED
|
@@ -1,4 +1,9 @@
|
|
| 1 |
import 'package:openfoodfacts/openfoodfacts.dart';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
Future<SearchResult> search(Map<String, String> query) {
|
| 4 |
var parametersList = <Parameter>[];
|
|
@@ -98,3 +103,49 @@ void mkConfiguration() {
|
|
| 98 |
|
| 99 |
OpenFoodAPIConfiguration.globalCountry = OpenFoodFactsCountry.CANADA;
|
| 100 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import 'package:openfoodfacts/openfoodfacts.dart';
|
| 2 |
+
import 'package:http/http.dart' as http;
|
| 3 |
+
// ignore_for_file: constant_identifier_names
|
| 4 |
+
import 'package:beautiful_soup_dart/beautiful_soup.dart';
|
| 5 |
+
import './types.dart';
|
| 6 |
+
|
| 7 |
|
| 8 |
Future<SearchResult> search(Map<String, String> query) {
|
| 9 |
var parametersList = <Parameter>[];
|
|
|
|
| 103 |
|
| 104 |
OpenFoodAPIConfiguration.globalCountry = OpenFoodFactsCountry.CANADA;
|
| 105 |
}
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
// function that scans for top steam charts
|
| 109 |
+
|
| 110 |
+
Future<List<SteamTopSeller>> findTopSteamSellers() async {
|
| 111 |
+
var url = Uri.https('store.steampowered.com', 'search/?filter=topsellers');
|
| 112 |
+
var html = await http.get(url);
|
| 113 |
+
return parseSteamTopSellers(html.body);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
List<SteamTopSeller> parseSteamTopSellers(String rawHTML ) {
|
| 117 |
+
BeautifulSoup soup = BeautifulSoup(rawHTML);
|
| 118 |
+
var searchResultsDiv = soup.find('div', attrs: {'id': 'search_resultsRows'});
|
| 119 |
+
if (searchResultsDiv == null) {
|
| 120 |
+
return <SteamTopSeller>[];
|
| 121 |
+
}
|
| 122 |
+
var topSellers = searchResultsDiv.findAll('a');
|
| 123 |
+
|
| 124 |
+
if (topSellers.isEmpty) {
|
| 125 |
+
return <SteamTopSeller>[];
|
| 126 |
+
}
|
| 127 |
+
var topSellersList = <SteamTopSeller>[];
|
| 128 |
+
for (var topSeller in topSellers) {
|
| 129 |
+
var imageDiv = topSeller.find('img');
|
| 130 |
+
String? imageSrc = '';
|
| 131 |
+
if (imageDiv != null) {
|
| 132 |
+
imageSrc = imageDiv.attributes['src'];
|
| 133 |
+
}
|
| 134 |
+
var title = topSeller.find('span', attrs: {'class': 'title'})?.text;
|
| 135 |
+
var publishDate = topSeller.find('div', attrs: {'class': 'col search_released responsive_secondrow'})?.text;
|
| 136 |
+
// var publishDate = topSeller.find('div', attrs: {'class': 'tab_item_top_tags'}).text;
|
| 137 |
+
// get data-price-final
|
| 138 |
+
var price = topSeller.find('div', attrs: {'class': 'search_price_discount_combined'})?.attributes['data-price-final'];
|
| 139 |
+
var discountDiv = topSeller.find('div', attrs: {'class': 'search_discount'});
|
| 140 |
+
String discount = "";
|
| 141 |
+
if (discountDiv != null) {
|
| 142 |
+
var discountSpan = discountDiv.find("span");
|
| 143 |
+
if (discountSpan != null) {
|
| 144 |
+
discount = discountSpan.text;
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
topSellersList.add(SteamTopSeller(imageSrc, title, price, publishDate, discount));
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
return topSellersList;
|
| 151 |
+
}
|
lib/types.dart
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class SteamTopSeller {
|
| 2 |
+
String? imageSrc;
|
| 3 |
+
String? title;
|
| 4 |
+
String? price;
|
| 5 |
+
String? publishDate;
|
| 6 |
+
String? discount;
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
SteamTopSeller(this.imageSrc, this.title, this.price, this.publishDate, this.discount);
|
| 10 |
+
|
| 11 |
+
fromJson(Map<String, dynamic> json) {
|
| 12 |
+
this.imageSrc = json['imageSrc'];
|
| 13 |
+
this.title = json['title'];
|
| 14 |
+
this.price = json['price'];
|
| 15 |
+
this.publishDate = json['publishDate'];
|
| 16 |
+
this.discount = json['discount'];
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
Map<String, dynamic> toJson() {
|
| 20 |
+
return {
|
| 21 |
+
'imageSrc': this.imageSrc,
|
| 22 |
+
'title': this.title,
|
| 23 |
+
'price': this.price,
|
| 24 |
+
'publishDate': this.publishDate,
|
| 25 |
+
'discount': this.discount,
|
| 26 |
+
};
|
| 27 |
+
}
|
| 28 |
+
}
|
pubspec.lock
CHANGED
|
@@ -36,6 +36,13 @@ packages:
|
|
| 36 |
url: "https://pub.dartlang.org"
|
| 37 |
source: hosted
|
| 38 |
version: "2.9.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
boolean_selector:
|
| 40 |
dependency: transitive
|
| 41 |
description:
|
|
@@ -71,6 +78,13 @@ packages:
|
|
| 71 |
url: "https://pub.dartlang.org"
|
| 72 |
source: hosted
|
| 73 |
version: "3.0.2"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
file:
|
| 75 |
dependency: transitive
|
| 76 |
description:
|
|
@@ -92,8 +106,15 @@ packages:
|
|
| 92 |
url: "https://pub.dartlang.org"
|
| 93 |
source: hosted
|
| 94 |
version: "2.1.1"
|
| 95 |
-
|
| 96 |
dependency: transitive
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
description:
|
| 98 |
name: http
|
| 99 |
url: "https://pub.dartlang.org"
|
|
|
|
| 36 |
url: "https://pub.dartlang.org"
|
| 37 |
source: hosted
|
| 38 |
version: "2.9.0"
|
| 39 |
+
beautiful_soup_dart:
|
| 40 |
+
dependency: "direct main"
|
| 41 |
+
description:
|
| 42 |
+
name: beautiful_soup_dart
|
| 43 |
+
url: "https://pub.dartlang.org"
|
| 44 |
+
source: hosted
|
| 45 |
+
version: "0.3.0"
|
| 46 |
boolean_selector:
|
| 47 |
dependency: transitive
|
| 48 |
description:
|
|
|
|
| 78 |
url: "https://pub.dartlang.org"
|
| 79 |
source: hosted
|
| 80 |
version: "3.0.2"
|
| 81 |
+
csslib:
|
| 82 |
+
dependency: transitive
|
| 83 |
+
description:
|
| 84 |
+
name: csslib
|
| 85 |
+
url: "https://pub.dartlang.org"
|
| 86 |
+
source: hosted
|
| 87 |
+
version: "0.17.2"
|
| 88 |
file:
|
| 89 |
dependency: transitive
|
| 90 |
description:
|
|
|
|
| 106 |
url: "https://pub.dartlang.org"
|
| 107 |
source: hosted
|
| 108 |
version: "2.1.1"
|
| 109 |
+
html:
|
| 110 |
dependency: transitive
|
| 111 |
+
description:
|
| 112 |
+
name: html
|
| 113 |
+
url: "https://pub.dartlang.org"
|
| 114 |
+
source: hosted
|
| 115 |
+
version: "0.15.1"
|
| 116 |
+
http:
|
| 117 |
+
dependency: "direct main"
|
| 118 |
description:
|
| 119 |
name: http
|
| 120 |
url: "https://pub.dartlang.org"
|
pubspec.yaml
CHANGED
|
@@ -8,6 +8,8 @@ environment:
|
|
| 8 |
|
| 9 |
dependencies:
|
| 10 |
alfred: ^1.0.0+1
|
|
|
|
|
|
|
| 11 |
openfoodfacts: ^2.2.1
|
| 12 |
|
| 13 |
dev_dependencies:
|
|
|
|
| 8 |
|
| 9 |
dependencies:
|
| 10 |
alfred: ^1.0.0+1
|
| 11 |
+
beautiful_soup_dart: ^0.3.0
|
| 12 |
+
http: ^0.13.5
|
| 13 |
openfoodfacts: ^2.2.1
|
| 14 |
|
| 15 |
dev_dependencies:
|
test/core_test.dart
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// load sample.html and run findTopSteamSellers, expect list of top steam sellers
|
| 2 |
+
import 'dart:io';
|
| 3 |
+
import 'package:test/test.dart';
|
| 4 |
+
import "package:dart_off_server/core.dart" as core;
|
| 5 |
+
import "package:path/path.dart" as p;
|
| 6 |
+
|
| 7 |
+
void main() {
|
| 8 |
+
test('calculate', () {
|
| 9 |
+
var rawHTMLPath = p.join(p.current, 'test', 'sample.html');
|
| 10 |
+
// load rawHTML from rawHTMLPath
|
| 11 |
+
File file = File(rawHTMLPath);
|
| 12 |
+
var rawHTML = file.readAsStringSync();
|
| 13 |
+
var steamSellers = core.parseSteamTopSellers(rawHTML);
|
| 14 |
+
// greater than 5
|
| 15 |
+
expect(steamSellers.length, greaterThan(5));
|
| 16 |
+
});
|
| 17 |
+
}
|
test/sample.html
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|