Merge lp:~jeremy-munsch/synapse-project/steam-plugin into lp:synapse-project

Proposed by Jeremy Munsch on 2015-11-22
Status: Needs review
Proposed branch: lp:~jeremy-munsch/synapse-project/steam-plugin
Merge into: lp:synapse-project
Diff against target: 265 lines (+239/-0)
3 files modified
src/plugins/Makefile.am (+1/-0)
src/plugins/steam-plugin.vala (+237/-0)
src/ui/synapse-main.vala (+1/-0)
To merge this branch: bzr merge lp:~jeremy-munsch/synapse-project/steam-plugin
Reviewer Review Type Date Requested Status
Rico Tzschichholz 2015-11-22 Pending
Review via email: mp+278256@code.launchpad.net

Description of the change

add steam plugin for games search and action providers
no dependencies

To post a comment you must log in.
634. By Rico Tzschichholz on 2015-11-30

ui/controller: Some optimization accessing model.query[] in search*()

635. By Rico Tzschichholz on 2015-11-30

core/query: Cache and reuse Regex.escape_string (query)

636. By Rico Tzschichholz on 2015-11-30

debian: Bump build-deps accordingly

637. By Rico Tzschichholz on 2016-02-26

plugins: Add suport for MATE Screensaver

638. By Rico Tzschichholz on 2016-02-26

po: Update translations

639. By Rico Tzschichholz on 2016-02-27

desktop-file-plugin: correct ApplicationsMatch to DesktopFileMatch

640. By Rico Tzschichholz on 2016-02-27

src: Drop "using Gee;"

641. By Rico Tzschichholz on 2016-02-27

src: Drop "using Json;"

642. By Rico Tzschichholz on 2016-02-27

src: Drop "using Zeitgeist;"

643. By Rico Tzschichholz on 2016-02-27

src: Drop "using Gtk;"

644. By Rico Tzschichholz on 2016-02-27

src: Drop "using Cairo;"

645. By Rico Tzschichholz on 2016-02-27

src: Drop last usages of "using *;"

646. By Rico Tzschichholz on 2016-02-27

ui: Show release-name in about-dialog only

647. By Rico Tzschichholz on 2016-02-27

ui: Bump to 2016

648. By Rico Tzschichholz on 2016-02-28

Release 0.2.99.2

649. By Rico Tzschichholz on 2016-03-02

ui: Set and update client-window of Gtk.IMMulticontext

650. By Rico Tzschichholz on 2016-03-08

main: Properly construct OptionEntry

Stop using an empty string where is getting treated as translateable.

651. By Michael Aquilina on 2016-04-01

Add pass plugin

652. By Rico Tzschichholz on 2016-09-29

Fix non-matching generic types

653. By Rico Tzschichholz on 2016-10-06

Fix non-matching generic types of interface implementations

654. By Jeremy Munsch on 2016-12-16

add steam plugin

Unmerged revisions

654. By Jeremy Munsch on 2016-12-16

add steam plugin

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/plugins/Makefile.am'
2--- src/plugins/Makefile.am 2016-04-01 05:58:51 +0000
3+++ src/plugins/Makefile.am 2016-12-16 20:48:59 +0000
4@@ -53,6 +53,7 @@
5 test-slow-plugin.vala \
6 xnoise-media-player-plugin.vala \
7 system-management.vala \
8+ steam-plugin.vala \
9 zeal-plugin.vala \
10 $(NULL)
11
12
13=== added file 'src/plugins/steam-plugin.vala'
14--- src/plugins/steam-plugin.vala 1970-01-01 00:00:00 +0000
15+++ src/plugins/steam-plugin.vala 2016-12-16 20:48:59 +0000
16@@ -0,0 +1,237 @@
17+/*
18+ * Copyright (C) 2015 Jérémy Munsch <jeremy.munsch@gmail.com>
19+ *
20+ * This program is free software; you can redistribute it and/or modify
21+ * it under the terms of the GNU General Public License as published by
22+ * the Free Software Foundation; either version 2 of the License, or
23+ * (at your option) any later version.
24+ *
25+ * This program is distributed in the hope that it will be useful,
26+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28+ * GNU General Public License for more details.
29+ *
30+ * You should have received a copy of the GNU General Public License
31+ * along with this program; if not, write to the Free Software
32+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
33+ *
34+ */
35+
36+namespace Synapse
37+{
38+ public class SteamPlugin : Object, Activatable, ItemProvider, ActionProvider
39+ {
40+ public bool enabled { get; set; default = true; }
41+
42+ public static string steam_games_dir { get; private set; default = ".steam/SteamApps"; }
43+
44+ private Gee.List<SteamGameMatch> games;
45+ private Gee.List<SteamAction> actions;
46+
47+ public void activate ()
48+ {
49+ parse_steam_games.begin ();
50+ }
51+
52+ public void deactivate ()
53+ {
54+ }
55+
56+ static void register_plugin ()
57+ {
58+ PluginRegistry.get_default ().register_plugin (
59+ typeof (SteamPlugin),
60+ _("Steam"),
61+ _("Browse and launch your steam games"),
62+ "steam",
63+ register_plugin,
64+ Environment.find_program_in_path ("steam") != null,
65+ _("Unable to find \"steam\" program")
66+ );
67+ }
68+
69+ static construct
70+ {
71+ register_plugin ();
72+ steam_games_dir = Path.build_filename (Environment.get_home_dir (), steam_games_dir);
73+ }
74+
75+ construct
76+ {
77+ games = new Gee.ArrayList<SteamGameMatch> ();
78+ actions = new Gee.ArrayList<SteamAction> ();
79+ actions.add (new SteamAction (_("Start game"), _("Launch the game through Steam"), "steam steam://rungameid/%s", MatchScore.HIGHEST));
80+ actions.add (new SteamAction (_("Open store"), _("Go to the game store"), "steam steam://store/%s"));
81+ actions.add (new SteamAction (_("Open newspage"), _("Go to the game newspage"), "steam steam://appnews/%s"));
82+ actions.add (new SteamAction (_("Check system requirement"), _("Check if the system meets the game requirement"), "steam steam://checksysreqs/%s"));
83+ actions.add (new SteamAction (_("Backup"), _("Launch the backup wizard"), "steam steam://backup/%s"));
84+ }
85+
86+ public bool handles_query (Query query)
87+ {
88+ return (QueryFlags.APPLICATIONS in query.query_type);
89+ }
90+
91+ public async ResultSet? search (Query q) throws SearchError
92+ {
93+ var results = new ResultSet ();
94+
95+ var matchers = Query.get_matchers_for_query (q.query_string, MatcherFlags.NO_FUZZY, RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS);
96+ foreach (var matcher in matchers)
97+ {
98+ foreach (var game in games)
99+ {
100+ q.check_cancellable ();
101+ if (matcher.key.match (game.title))
102+ results.add (game, matcher.value);
103+ }
104+ }
105+ return results;
106+ }
107+
108+ public ResultSet? find_for_match (ref Query q, Match match)
109+ {
110+ if (!actions[0].valid_for_match (match))
111+ return null;
112+
113+ var matchers = Query.get_matchers_for_query (q.query_string, 0, RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS);
114+
115+ var results = new ResultSet ();
116+ foreach (var matcher in matchers)
117+ {
118+ foreach (var action in actions)
119+ {
120+ if (matcher.key.match (action.title))
121+ results.add (action, matcher.value + action.default_relevancy);
122+ }
123+ }
124+ return results;
125+ }
126+
127+
128+ /**
129+ * Actions
130+ */
131+
132+ private class SteamAction : Action
133+ {
134+ public string command { get; set; }
135+
136+ public SteamAction (string title, string description, string command, int default_relevancy = MatchScore.AVERAGE)
137+ {
138+ Object (title: title,
139+ description: description,
140+ icon_name: "steam",
141+ has_thumbnail: false);
142+ this.command = command;
143+ this.default_relevancy = default_relevancy;
144+ }
145+
146+ public override bool valid_for_match (Match match)
147+ {
148+ return (match is SteamGameMatch);
149+ }
150+
151+ public override void do_execute (Match match, Match? target = null)
152+ {
153+ string cmd = command.printf (((SteamGameMatch)match).app_id);
154+ try
155+ {
156+ AppInfo ai = AppInfo.create_from_commandline (cmd, "steam", 0);
157+ if (!ai.launch (null, null))
158+ warning ("Could not launch Steam %s".printf (cmd));
159+ }
160+ catch (Error err)
161+ {
162+ warning ("Could not launch %s %s", cmd, err.message);
163+ }
164+ }
165+ }
166+
167+
168+ /**
169+ * Match
170+ */
171+
172+ private class SteamGameMatch : Match
173+ {
174+ public string app_id { get; set; }
175+ public string name { get; set; }
176+
177+ public SteamGameMatch (string app_id, string name)
178+ {
179+ Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default ();
180+ Gtk.IconInfo? icon_info = icon_theme.lookup_icon ("steam_icon_%s".printf (app_id), 48, 0);
181+
182+ Object (title: "Steam %s".printf (name),
183+ description : "",
184+ icon_name: icon_info != null ? "steam_icon_%s".printf (app_id) : "steam",
185+ has_thumbnail: false);
186+ this.app_id = app_id;
187+ this.name = name;
188+ }
189+ }
190+
191+
192+ /**
193+ * private methods
194+ */
195+
196+ private async void parse_steam_games ()
197+ {
198+ try
199+ {
200+ File steam_apps = File.new_for_path (steam_games_dir);
201+
202+ FileEnumerator enumerator = steam_apps.enumerate_children (
203+ "standard::*",
204+ FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
205+
206+ FileInfo info = null;
207+ while ((info = enumerator.next_file ()) != null)
208+ {
209+ Idle.add_full (Priority.DEFAULT_IDLE, parse_steam_games.callback);
210+ yield;
211+ if (info.get_file_type () == FileType.REGULAR && Regex.match_simple ("appmanifest_[0-9]*.acf", info.get_name ()))
212+ {
213+ try
214+ {
215+ string app_id = null, app_name = null;
216+
217+ File file = File.new_for_path (Path.build_filename (steam_games_dir, info.get_name ()));
218+
219+ FileInputStream @is = file.read ();
220+ DataInputStream dis = new DataInputStream (@is);
221+ string line;
222+
223+ while ((line = dis.read_line ()) != null) {
224+ if (null == app_id && -1 != line.index_of ("\"appid\""))
225+ app_id = (new Regex ("(?:\t* *\"[a-zA-Z]+\"\t)|\"|\t")).replace (line, line.length, 0, "").strip ();
226+ if (null == app_name && -1 != line.index_of ("\"name\""))
227+ app_name = (new Regex ("(?:\t* *\"[a-zA-Z]+\"\t)|\"|\t")).replace (line, line.length, 0, "").strip ();
228+ if (null != app_id && null != app_name)
229+ break;
230+ }
231+
232+ if (null == app_id && null == app_name)
233+ {
234+ message ("Was not able to parse Steam app manifest %s".printf (Path.build_filename (steam_games_dir, info.get_name ())));
235+ break;
236+ }
237+
238+ games.add (new SteamGameMatch (app_id, app_name));
239+ }
240+ catch (Error e)
241+ {
242+ warning ("%s", e.message);
243+ }
244+ }
245+ }
246+ }
247+ catch (Error e)
248+ {
249+ warning ("%s".printf (e.message));
250+ }
251+ }
252+ }
253+}
254
255=== modified file 'src/ui/synapse-main.vala'
256--- src/ui/synapse-main.vala 2016-04-01 05:58:51 +0000
257+++ src/ui/synapse-main.vala 2016-12-16 20:48:59 +0000
258@@ -176,6 +176,7 @@
259 typeof (PidginPlugin),
260 typeof (PassPlugin),
261 typeof (ChatActions),
262+ typeof (SteamPlugin),
263 typeof (ZealPlugin),
264 #if HAVE_ZEITGEIST
265 typeof (ZeitgeistPlugin),