Merge lp:~tintou/noise/noise-gda-zeitgeist into lp:~elementary-apps/noise/trunk

Proposed by Corentin Noël
Status: Merged
Approved by: Danielle Foré
Approved revision: 1835
Merged at revision: 1827
Proposed branch: lp:~tintou/noise/noise-gda-zeitgeist
Merge into: lp:~elementary-apps/noise/trunk
Diff against target: 9601 lines (+4689/-2507)
68 files modified
CMakeLists.txt (+4/-20)
core/CMakeLists.txt (+0/-1)
core/Devices/Device.vala (+4/-5)
core/Devices/DeviceManager.vala (+0/-21)
core/LibrariesManager.vala (+9/-5)
core/Library.vala (+7/-7)
core/Media.vala (+1/-1)
core/Playlists/Playlist.vala (+3/-3)
core/Playlists/SmartPlaylist.vala (+45/-61)
core/Playlists/SmartQuery.vala (+2/-3)
core/Settings.vala (+2/-2)
core/Utils/Search.vala (+10/-6)
core/Utils/String.vala (+6/-3)
plugins/CMakeLists.txt (+0/-1)
plugins/Devices/AudioPlayers/AudioPlayerDevice.vala (+6/-17)
plugins/Devices/AudioPlayers/AudioPlayerLibrary.vala (+21/-101)
plugins/Devices/CDRom/CDRomDevice.vala (+2/-6)
plugins/Devices/CDRom/CDViewWrapper.vala (+1/-1)
plugins/Devices/iPod/iPodDevice.vala (+1/-12)
plugins/Devices/iPod/iPodLibrary.vala (+32/-179)
plugins/Devices/iPod/iPodPlaylistHelper.vala (+47/-69)
plugins/LastFM/Core.vala (+83/-82)
plugins/LastFM/LastFM.vala (+1/-1)
plugins/LastFM/SimilarMedia.vala (+25/-32)
plugins/LastFM/SimilarMediaWidget.vala (+1/-3)
plugins/LastFM/noise-lastfm.application (+5/-0)
plugins/MPRIS/MPRIS.vala (+1/-1)
plugins/Zeitgeist/CMakeLists.txt (+0/-34)
plugins/Zeitgeist/Zeitgeist.vala (+0/-88)
plugins/Zeitgeist/zeitgeist.plugin (+0/-9)
schemas/org.pantheon.noise.gschema.xml (+5/-5)
src/CMakeLists.txt (+5/-3)
src/DataBase.vala (+267/-35)
src/DataBase/DataBaseManager.vala (+0/-937)
src/DataBase/DataBaseUpdater.vala (+0/-87)
src/Dialogs/FileNotFoundDialog.vala (+1/-1)
src/Dialogs/MediaEditor.vala (+21/-21)
src/Dialogs/SmartPlaylistEditor.vala (+21/-15)
src/FileOperator.vala (+1/-1)
src/LibraryWindow.vala (+115/-133)
src/LocalBackend/DevicePreferences.vala (+161/-20)
src/LocalBackend/LocalLibrary.vala (+297/-141)
src/LocalBackend/LocalMedia.vala (+111/-64)
src/LocalBackend/LocalSmartPlaylist.vala (+268/-0)
src/LocalBackend/LocalStaticPlaylist.vala (+90/-0)
src/Objects/HistoryPlaylist.vala (+589/-0)
src/PlaybackManager.vala (+14/-25)
src/Views/ContentView.vala (+1/-1)
src/Views/DeviceSummaryWidget.vala (+22/-34)
src/Views/DeviceView.vala (+9/-10)
src/Views/GridView/GridLayout.vala (+3/-3)
src/Views/GridView/GridView.vala (+10/-36)
src/Views/GridView/PopupListView.vala (+3/-3)
src/Views/ListView/ListView.vala (+9/-10)
src/Views/ListView/Lists/CellDataFunctionHelper.vala (+1/-1)
src/Views/ListView/Lists/GenericList.vala (+25/-32)
src/Views/ListView/Lists/ListColumn.vala (+1/-0)
src/Views/ListView/Lists/MusicListView.vala (+20/-47)
src/Views/ListView/Lists/TreeViewSetup.vala (+96/-22)
src/Views/Wrappers/DeviceViewWrapper.vala (+1/-1)
src/Views/Wrappers/MusicViewWrapper.vala (+5/-5)
src/Views/Wrappers/PlaylistViewWrapper.vala (+13/-27)
src/Views/Wrappers/ViewWrapper.vala (+4/-6)
src/Widgets/FastView/FastGrid.vala (+6/-6)
src/Widgets/TopDisplay.vala (+1/-1)
src/main.vala (+1/-0)
vapi/libgda-5.0.deps (+1/-0)
vapi/libgda-5.0.vapi (+2172/-0)
To merge this branch: bzr merge lp:~tintou/noise/noise-gda-zeitgeist
Reviewer Review Type Date Requested Status
xapantu (community) Approve
Review via email: mp+269248@code.launchpad.net

Commit message

Changed SQLHeavy to libGDA. Added Zeitgeist History.

Description of the change

Switched to GDA.
A lot of changes have been made in the structure of the application.
Playlists, Smart Playlists, Media, Device preferences and TreeView Headers are now directly using the database.
We need to provide the right .vapi until the release of libgda 6.0

The History playlist is now using Zeitgeist directly

Overall, big changes and (I hope) more stability.

To post a comment you must log in.
Revision history for this message
Danielle Foré (danrabbit) wrote :

So far my only real complaints (besides issues present in trunk ofc) are:

* The duplication in the history playlist.
* Making sure we restore with the last-played track

I'm on the look out for crashes or any other weirdness :D

lp:~tintou/noise/noise-gda-zeitgeist updated
1833. By Corentin Noël

Ensure that History Playlist doesn't contain duplicates.

Revision history for this message
Viko Adi Rahmawan (vikoadi) wrote :

Searching crash the apps

Is it planned to ditch the whole _medias and _searched_medias? We can use gda query to search that. I think that would be more memory efficient.

lp:~tintou/noise/noise-gda-zeitgeist updated
1834. By Corentin Noël

Fixed rating parsing. Searchs now directly with the database.

1835. By Corentin Noël

Search for rating if the user search with only wildcards.

Revision history for this message
Corentin Noël (tintou) wrote :

Daniel:
 * The history playlist is now deduplicated.
 * last-played bug is now fixed in granite
Viko Adi:
 * It now uses the Database directly, but _medias and _searched_medias are still required because we need to cache some values once they're retrieved from the database.

Revision history for this message
Danielle Foré (danrabbit) wrote :

Cody is working on the new granite release including an so name bump. So I guess this branch will need to require the new version of granite before it can be merged.

I can confirm that the history playlist is de-duplicated

I cannot confirm that search crashes the app.

Revision history for this message
Danielle Foré (danrabbit) wrote :

I can confirm that after the granite update that the last played song is restored.

However, I'm getting this behavior where only the statusbar will show, then the rest of the UI. It's pretty odd. Anyone can reproduce?

Revision history for this message
Viko Adi Rahmawan (vikoadi) wrote :

@Daniel seems that media loading in initialize_library is too slow in large library, maybe we should run it on async thread, running search in thread seems to be good idea too.

Revision history for this message
Viko Adi Rahmawan (vikoadi) wrote :

Search works great now

@Daniel seems that media loading in initialize_library is too slow in large library, maybe we should run it on async thread, running search in thread seems to be good idea too.

Revision history for this message
xapantu (xapantu) wrote :

The code looks fine (but the diff is very long). I have some issues with sorting on Archlinux, but after some discussions, it appears that it could be caused by a newer gtk and a newer gda. Anyway, this should be merged in trunk so as this work can be carried on.

The import is slow, but it was also slow with the trunk, so probably nothing new here.

review: Approve
Revision history for this message
Danielle Foré (danrabbit) wrote :

Since Lucas marked this as "approve", I'm going to move the status of the MR to "approve" as well

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-04-06 19:13:13 +0000
3+++ CMakeLists.txt 2015-08-27 10:21:27 +0000
4@@ -86,11 +86,15 @@
5 set (DEPS_PACKAGES
6 ${CORE_LIBRARY_NAME}
7 ${CORE_PACKAGES} # this is needed until we provide a ${CORE_LIBRARY_NAME}.deps file
8+ libgda-5.0
9 taglib_c
10+ zeitgeist-2.0
11 )
12
13 set (DEPS_PKG
14+ libgda-5.0
15 taglib_c
16+ zeitgeist-2.0
17 )
18
19 find_package (PkgConfig)
20@@ -113,26 +117,6 @@
21 )
22
23 #
24-# SQLHeavy: Use version 0.2 if it is available; otherwise, fall back to 0.1
25-#
26-pkg_check_modules (SQLHEAVY2 QUIET sqlheavy-0.2)
27-if (SQLHEAVY2_FOUND)
28- message ("-- Will use sqlheavy-0.2")
29- set (DEPS_PACKAGES ${DEPS_PACKAGES} sqlheavy-0.2)
30- set (SQLHEAVY_CFLAGS ${SQLHEAVY2_CFLAGS})
31- set (SQLHEAVY_LIBRARY_DIRS ${SQLHEAVY2_LIBRARY_DIRS})
32- set (SQLHEAVY_LIBRARIES ${SQLHEAVY2_LIBRARIES})
33-else ()
34- message ("-- Will use sqlheavy-0.1")
35- pkg_check_modules (SQLHEAVY REQUIRED sqlheavy-0.1)
36- set (DEPS_PACKAGES ${DEPS_PACKAGES} sqlheavy-0.1)
37-endif ()
38-
39-set (DEPS_CFLAGS ${DEPS_CFLAGS} ${SQLHEAVY_CFLAGS})
40-set (DEPS_LIBRARIES ${DEPS_LIBRARIES} ${SQLHEAVY_LIBRARIES})
41-set (DEPS_LIBRARY_DIRS ${DEPS_LIBRARY_DIRS} ${SQLHEAVY_LIBRARY_DIRS})
42-
43-#
44 # Libnotify
45 #
46 pkg_check_modules (LIBNOTIFY QUIET libnotify)
47
48=== modified file 'core/CMakeLists.txt'
49--- core/CMakeLists.txt 2015-05-24 21:40:48 +0000
50+++ core/CMakeLists.txt 2015-08-27 10:21:27 +0000
51@@ -29,7 +29,6 @@
52 Devices/Device.vala
53 Devices/NetworkDevice.vala
54 Devices/DeviceManager.vala
55- Devices/DevicePreferences.vala
56 Playlists/Playlist.vala
57 Playlists/StaticPlaylist.vala
58 Playlists/SmartPlaylist.vala
59
60=== modified file 'core/Devices/Device.vala'
61--- core/Devices/Device.vala 2015-06-12 13:51:08 +0000
62+++ core/Devices/Device.vala 2015-08-27 10:21:27 +0000
63@@ -34,8 +34,7 @@
64 public signal void initialized (Device d);
65 public signal void device_unmounted ();
66 public signal void infobar_message (string message, Gtk.MessageType type);
67-
68- public abstract DevicePreferences get_preferences();
69+
70 public abstract bool start_initialization();
71 public abstract void finish_initialization();
72 public abstract string getContentType();
73@@ -113,9 +112,9 @@
74 return get_capacity () > (list_size - without_size);
75 }
76 }
77-
78- public string get_unique_identifier() {
79- Mount? m = get_mount();
80+
81+ public virtual string get_unique_identifier () {
82+ Mount? m = get_mount ();
83 if (m != null) {
84 string uuid = m.get_uuid();
85 File root = m.get_root();
86
87=== modified file 'core/Devices/DeviceManager.vala'
88--- core/Devices/DeviceManager.vala 2015-06-12 13:51:08 +0000
89+++ core/Devices/DeviceManager.vala 2015-08-27 10:21:27 +0000
90@@ -39,7 +39,6 @@
91 public signal void mount_added (Mount mount);
92 public signal void mount_removed (Mount mount);
93
94- private Gee.TreeSet<DevicePreferences> device_preferences;
95 private Gee.TreeSet<unowned Device> initialized_devices;
96 private Gee.TreeSet<unowned Mount> mounts_availables;
97 private Gee.TreeSet<Playlist> local_playlists;
98@@ -53,7 +52,6 @@
99 }
100
101 private DeviceManager () {
102- device_preferences = new Gee.TreeSet<DevicePreferences> ();
103 initialized_devices = new Gee.TreeSet<unowned Device> ();
104 mounts_availables = new Gee.TreeSet<unowned Mount> ();
105 local_playlists = new Gee.TreeSet<Playlist> ();
106@@ -67,10 +65,6 @@
107 get_pre_existing_mounts.begin ();
108 }
109
110- public void set_device_preferences (Gee.Collection<DevicePreferences> device_preferences) {
111- this.device_preferences.add_all (device_preferences);
112- }
113-
114 public async void get_pre_existing_mounts () {
115 var mounts = new Gee.TreeSet<Mount> ();
116 var volumes = new Gee.TreeSet<Volume> ();
117@@ -118,15 +112,6 @@
118 //message ("mount_preunmount:%s\n", mount.get_uuid());
119 }
120
121- public DevicePreferences? get_device_preferences (string id) {
122- foreach (var device in device_preferences) {
123- if (device.id == id)
124- return device;
125- }
126-
127- return null;
128- }
129-
130 public Gee.Collection<unowned Device> get_initialized_devices () {
131 return initialized_devices;
132 }
133@@ -134,10 +119,4 @@
134 public Gee.Collection<unowned Mount> get_available_mounts () {
135 return mounts_availables;
136 }
137-
138- public void add_device_preferences (DevicePreferences dp) {
139- lock (device_preferences) {
140- device_preferences.add (dp);
141- }
142- }
143 }
144
145=== modified file 'core/LibrariesManager.vala'
146--- core/LibrariesManager.vala 2015-06-12 13:51:08 +0000
147+++ core/LibrariesManager.vala 2015-08-27 10:21:27 +0000
148@@ -29,21 +29,25 @@
149 */
150
151 public class Noise.LibrariesManager : GLib.Object {
152-
153+ /**
154+ * Headless playlists are playlists that are not linked to a library.
155+ */
156+ public signal void add_headless_playlist (StaticPlaylist playlist);
157+
158 public signal void library_removed (Library library);
159 public signal void library_added (Library library);
160-
161+
162 public signal void cancel_transfer ();
163 public signal void operation_terminated ();
164-
165+
166 public double progress;
167 public string current_operation;
168 private string old_search = null;
169-
170+
171 private Gee.HashMap<Library, int> libraries;
172 private int current_index = 0;
173 public Library local_library;
174-
175+
176 public LibrariesManager () {
177 libraries = new Gee.HashMap<Library, int> ();
178 }
179
180=== modified file 'core/Library.vala'
181--- core/Library.vala 2015-06-12 13:51:08 +0000
182+++ core/Library.vala 2015-08-27 10:21:27 +0000
183@@ -66,9 +66,9 @@
184 public abstract Media? find_media (Media to_find);
185 public abstract Media? media_from_file (File file);
186 public abstract Media? media_from_uri (string uri);
187- public abstract Media? media_from_id (int id);
188+ public abstract Media? media_from_id (int64 id);
189 public abstract Gee.Collection<Media> medias_from_uris (Gee.Collection<string> uris);
190- public abstract Gee.Collection<Media> medias_from_ids (Gee.Collection<int> ids);
191+ public abstract Gee.Collection<Media> medias_from_ids (Gee.Collection<int64?> ids);
192 public abstract void update_media (Media s, bool updateMeta, bool record_time);
193 public abstract void update_medias (Gee.Collection<Media> updates, bool updateMeta, bool record_time);
194 public abstract void remove_media (Media s, bool trash);
195@@ -76,14 +76,14 @@
196
197 public abstract bool support_smart_playlists ();
198 public abstract void add_smart_playlist (SmartPlaylist p);
199- public abstract void remove_smart_playlist (int id);
200- public abstract SmartPlaylist? smart_playlist_from_id (int id);
201+ public abstract void remove_smart_playlist (int64 id);
202+ public abstract SmartPlaylist? smart_playlist_from_id (int64 id);
203 public abstract SmartPlaylist? smart_playlist_from_name (string name);
204
205 public abstract bool support_playlists ();
206 public abstract void add_playlist (StaticPlaylist p);
207- public abstract void remove_playlist (int id);
208- public abstract StaticPlaylist? playlist_from_id (int id);
209+ public abstract void remove_playlist (int64 id);
210+ public abstract StaticPlaylist? playlist_from_id (int64 id);
211 public abstract StaticPlaylist? playlist_from_name (string name);
212
213 public abstract bool start_file_operations (string? message);
214@@ -99,7 +99,7 @@
215 return i;
216 }
217
218- public void media_from_name (Gee.Collection<Media> tests, Gee.Collection<int> found, Gee.Collection<Media> not_found) {
219+ public void media_from_name (Gee.Collection<Media> tests, Gee.Collection<int64?> found, Gee.Collection<Media> not_found) {
220 foreach (Media test in tests) {
221 var media_found = find_media (test);
222 if (media_found != null) {
223
224=== modified file 'core/Media.vala'
225--- core/Media.vala 2015-06-12 13:51:08 +0000
226+++ core/Media.vala 2015-08-27 10:21:27 +0000
227@@ -33,7 +33,7 @@
228 /// Used for unknown titles, artists, or album names.
229 protected static string UNKNOWN = _("Unknown");
230
231- public int rowid { get; set; }
232+ public int64 rowid { get; set; }
233
234 public virtual string uri {
235 owned get { return file.get_uri (); }
236
237=== modified file 'core/Playlists/Playlist.vala'
238--- core/Playlists/Playlist.vala 2015-06-12 14:41:35 +0000
239+++ core/Playlists/Playlist.vala 2015-08-27 10:21:27 +0000
240@@ -32,10 +32,10 @@
241 public signal void request_play ();
242 public virtual Gee.ArrayQueue<Media> medias { get; internal set; }
243
244- public int rowid { get; set; }
245+ public int64 rowid { get; set; }
246 public GLib.Icon icon;
247- private string _name = "";
248- public string name {
249+ internal string _name = "";
250+ public virtual string name {
251 get {
252 return _name;
253 }
254
255=== modified file 'core/Playlists/SmartPlaylist.vala'
256--- core/Playlists/SmartPlaylist.vala 2015-06-12 14:41:35 +0000
257+++ core/Playlists/SmartPlaylist.vala 2015-08-27 10:21:27 +0000
258@@ -35,14 +35,14 @@
259 ANY = false
260 }
261
262- public ConditionalType conditional { get; set; default = ConditionalType.ALL; }
263+ public virtual ConditionalType conditional { get; set; default = ConditionalType.ALL; }
264 public Gee.TreeSet<SmartQuery> queries;
265 public int query_count { get; set; default = 0; }
266
267- public bool limit { get; set; default = false; }
268- public int limit_amount { get; set; default = 50; }
269+ public virtual bool limit { get; set; default = false; }
270+ public virtual uint limit_amount { get; set; default = 50; }
271
272- private Noise.Library library;
273+ protected Noise.Library library;
274
275 /*
276 * A SmartPlaylist should be linked to only one library.
277@@ -142,112 +142,112 @@
278 switch (q.field) {
279 case Noise.SmartQuery.FieldType.ALBUM :
280 if(q.comparator == SmartQuery.ComparatorType.IS)
281- return q.value.down() == s.album.down();
282+ return q.value.get_string ().down () == s.album.down();
283 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
284- return (q.value.down() in s.album.down());
285+ return (q.value.get_string ().down() in s.album.down());
286 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
287- return !(q.value.down() in s.album.down());
288+ return !(q.value.get_string ().down() in s.album.down());
289 break;
290 case Noise.SmartQuery.FieldType.ARTIST:
291 if(q.comparator == SmartQuery.ComparatorType.IS)
292- return q.value.down() == s.artist.down();
293+ return q.value.get_string ().down() == s.artist.down();
294 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
295- return (q.value.down() in s.artist.down());
296+ return (q.value.get_string ().down() in s.artist.down());
297 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
298- return !(q.value.down() in s.artist.down());
299+ return !(q.value.get_string ().down() in s.artist.down());
300 break;
301 case Noise.SmartQuery.FieldType.COMPOSER:
302 if(q.comparator == SmartQuery.ComparatorType.IS)
303- return q.value.down() == s.composer.down();
304+ return q.value.get_string ().down() == s.composer.down();
305 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
306- return (q.value.down() in s.composer.down());
307+ return (q.value.get_string ().down() in s.composer.down());
308 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
309- return !(q.value.down() in s.composer.down());
310+ return !(q.value.get_string ().down() in s.composer.down());
311 break;
312 case Noise.SmartQuery.FieldType.COMMENT:
313 if(q.comparator == SmartQuery.ComparatorType.IS)
314- return q.value.down() == s.comment.down();
315+ return q.value.get_string ().down() == s.comment.down();
316 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
317- return (q.value.down() in s.comment.down());
318+ return (q.value.get_string ().down() in s.comment.down());
319 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
320- return !(q.value.down() in s.comment.down());
321+ return !(q.value.get_string ().down() in s.comment.down());
322 break;
323 case Noise.SmartQuery.FieldType.GENRE:
324 if(q.comparator == SmartQuery.ComparatorType.IS)
325- return q.value.down() == s.genre.down();
326+ return q.value.get_string ().down() == s.genre.down();
327 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
328- return (q.value.down() in s.genre.down());
329+ return (q.value.get_string ().down() in s.genre.down());
330 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
331- return !(q.value.down() in s.genre.down());
332+ return !(q.value.get_string ().down() in s.genre.down());
333 break;
334 case Noise.SmartQuery.FieldType.GROUPING:
335 if(q.comparator == SmartQuery.ComparatorType.IS)
336- return q.value.down() == s.grouping.down();
337+ return q.value.get_string ().down() == s.grouping.down();
338 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
339- return (q.value.down() in s.grouping.down());
340+ return (q.value.get_string ().down() in s.grouping.down());
341 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
342- return !(q.value.down() in s.grouping.down());
343+ return !(q.value.get_string ().down() in s.grouping.down());
344 break;
345 case Noise.SmartQuery.FieldType.TITLE:
346 if(q.comparator == SmartQuery.ComparatorType.IS)
347- return q.value.down() == s.title.down();
348+ return q.value.get_string ().down() == s.title.down();
349 else if(q.comparator == SmartQuery.ComparatorType.CONTAINS)
350- return (q.value.down() in s.title.down());
351+ return (q.value.get_string ().down() in s.title.down());
352 else if(q.comparator == SmartQuery.ComparatorType.NOT_CONTAINS)
353- return !(q.value.down() in s.title.down());
354+ return !(q.value.get_string ().down() in s.title.down());
355 break;
356 case Noise.SmartQuery.FieldType.BITRATE:
357 if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
358- return int.parse(q.value) == s.bitrate;
359+ return q.value.get_int () == s.bitrate;
360 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_MOST)
361- return (s.bitrate <= int.parse(q.value));
362+ return (s.bitrate <= q.value.get_int ());
363 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_LEAST)
364- return (s.bitrate >= int.parse(q.value));
365+ return (s.bitrate >= q.value.get_int ());
366 break;
367 case Noise.SmartQuery.FieldType.PLAYCOUNT:
368 if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
369- return int.parse(q.value) == s.play_count;
370+ return q.value.get_int () == s.play_count;
371 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_MOST)
372- return (s.play_count <= int.parse(q.value));
373+ return (s.play_count <= q.value.get_int ());
374 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_LEAST)
375- return (s.play_count >= int.parse(q.value));
376+ return (s.play_count >= q.value.get_int ());
377 break;
378 case Noise.SmartQuery.FieldType.SKIPCOUNT:
379 if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
380- return int.parse(q.value) == s.skip_count;
381+ return q.value.get_int () == s.skip_count;
382 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_MOST)
383- return (s.skip_count <= int.parse(q.value));
384+ return (s.skip_count <= q.value.get_int ());
385 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_LEAST)
386- return (s.skip_count >= int.parse(q.value));
387+ return (s.skip_count >= q.value.get_int ());
388 break;
389 case Noise.SmartQuery.FieldType.YEAR:
390 if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
391- return int.parse (q.value) == s.year;
392+ return q.value.get_int () == s.year;
393 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_MOST)
394- return (s.year <= int.parse (q.value));
395+ return (s.year <= q.value.get_int ());
396 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_LEAST)
397- return (s.year >= int.parse (q.value));
398+ return (s.year >= q.value.get_int ());
399 break;
400 case Noise.SmartQuery.FieldType.LENGTH:
401 if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
402- return int.parse (q.value) == s.length;
403+ return q.value.get_int () == s.length;
404 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_MOST)
405- return (s.length <= int.parse (q.value));
406+ return (s.length <= q.value.get_int ());
407 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_LEAST)
408- return (s.length >= int.parse (q.value));
409+ return (s.length >= q.value.get_int ());
410 break;
411 case Noise.SmartQuery.FieldType.RATING:
412 if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
413- return int.parse(q.value) == s.rating;
414+ return q.value.get_int () == s.rating;
415 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_MOST)
416- return (s.rating <= int.parse (q.value));
417+ return (s.rating <= q.value.get_int ());
418 else if(q.comparator == SmartQuery.ComparatorType.IS_AT_LEAST)
419- return (s.rating >= int.parse (q.value));
420+ return (s.rating >= q.value.get_int ());
421 break;
422 case Noise.SmartQuery.FieldType.DATE_ADDED:
423 var now = new DateTime.now_local ();
424 var played = new DateTime.from_unix_local (s.date_added);
425- played = played.add_days (int.parse (q.value));
426+ played = played.add_days (q.value.get_int ());
427
428 if (q.comparator == SmartQuery.ComparatorType.IS_EXACTLY) {
429 return (now.get_day_of_year () == played.get_day_of_year () && now.get_year () == played.get_year ());
430@@ -257,29 +257,13 @@
431 return now.compare (played) > 0;
432 }
433 break;
434- case Noise.SmartQuery.FieldType.DATE_RELEASED:
435-/*
436- var now = new DateTime.now_local();
437- var released = new DateTime.from_unix_local(s.podcast_date);
438- released = released.add_days(int.parse(q.value));
439-
440- if(q.comparator == SmartQuery.ComparatorType.IS_EXACTLY)
441- return (now.get_day_of_year() == released.get_day_of_year() && now.get_year() == released.get_year());
442- else if(q.comparator == SmartQuery.ComparatorType.IS_WITHIN) {
443- return released.compare(now) > 0;
444- }
445- else if(q.comparator == SmartQuery.ComparatorType.IS_BEFORE) {
446- return now.compare(released) > 0;
447- }
448-*/
449- break;
450 case Noise.SmartQuery.FieldType.LAST_PLAYED:
451 if(s.last_played == 0)
452 return false;
453
454 var now = new DateTime.now_local();
455 var played = new DateTime.from_unix_local (s.last_played);
456- played = played.add_days (int.parse (q.value));
457+ played = played.add_days (q.value.get_int ());
458
459 if (q.comparator == SmartQuery.ComparatorType.IS_EXACTLY) {
460 return (now.get_day_of_year () == played.get_day_of_year () && now.get_year () == played.get_year ());
461
462=== modified file 'core/Playlists/SmartQuery.vala'
463--- core/Playlists/SmartQuery.vala 2015-06-12 14:41:35 +0000
464+++ core/Playlists/SmartQuery.vala 2015-08-27 10:21:27 +0000
465@@ -49,7 +49,6 @@
466 COMMENT,
467 COMPOSER,
468 DATE_ADDED,
469- DATE_RELEASED,
470 GENRE,
471 GROUPING,
472 LAST_PLAYED,
473@@ -64,13 +63,13 @@
474 public int rowid { get; set; default = 0; }
475 public FieldType field { get; set; default = FieldType.ALBUM; }
476 public ComparatorType comparator { get; set; default = ComparatorType.IS; }
477- public string value { get; set; default = ""; } //internally this often holds numbers, but that's ok.
478+ public GLib.Value value { get; set; default = GLib.Value (typeof (int)); }
479
480 public SmartQuery () {
481
482 }
483
484- public SmartQuery.with_info (FieldType field, ComparatorType comparator, string value) {
485+ public SmartQuery.with_info (FieldType field, ComparatorType comparator, GLib.Value value) {
486 this.field = field;
487 this.comparator = comparator;
488 this.value = value;
489
490=== modified file 'core/Settings.vala'
491--- core/Settings.vala 2015-06-12 13:51:08 +0000
492+++ core/Settings.vala 2015-08-27 10:21:27 +0000
493@@ -67,8 +67,8 @@
494 public bool write_metadata_to_file { get; set; }
495 public bool copy_imported_music { get; set; }
496 public bool close_while_playing { get; set; }
497- public int last_media_playing { get; set; }
498- public int last_playlist_playing { get; set; }
499+ public int64 last_media_playing { get; set; }
500+ public string last_playlist_playing { get; set; }
501 public int last_media_position { get; set; }
502 public Shuffle shuffle_mode { get; set; }
503 public Repeat repeat_mode { get; set; }
504
505=== modified file 'core/Utils/Search.vala'
506--- core/Utils/Search.vala 2015-06-12 13:51:08 +0000
507+++ core/Utils/Search.vala 2015-08-27 10:21:27 +0000
508@@ -109,18 +109,22 @@
509 * " "
510 * "**a"
511 */
512- public inline int get_rating_from_string (string rating_string)
513- ensures (result != 0 || result == -1)
514+ public inline uint? get_rating_from_string (string rating_string)
515+ ensures (result != 0)
516 {
517- int i;
518+ int i = 0;
519 unichar c;
520+ uint rating;
521
522- for (i = 0; rating_string.get_next_char (ref i, out c);) {
523+ for (rating = 0; rating_string.get_next_char (ref i, out c); rating++) {
524 if (c != '*')
525- return -1;
526+ return null;
527 }
528
529- return i > 0 ? i : -1;
530+ if (rating == 0)
531+ return null;
532+
533+ return rating;
534 }
535
536 public inline bool match_string_to_media (Media m, string search) {
537
538=== modified file 'core/Utils/String.vala'
539--- core/Utils/String.vala 2015-06-12 13:51:08 +0000
540+++ core/Utils/String.vala 2015-08-27 10:21:27 +0000
541@@ -178,13 +178,16 @@
542 * @param parsed_search_string location where the canonicalized version of the
543 * search string is stored. Should be passed to the methods in Noise.Search.
544 */
545- public static void base_search_method (string search, out int parsed_rating,
546+ public static void base_search_method (string search, out uint parsed_rating,
547 out string parsed_search_string)
548 {
549- parsed_rating = Search.get_rating_from_string (search.strip ());
550+ var result = Search.get_rating_from_string (search.strip ());
551
552- if (parsed_rating > 0)
553+ if (result != null) {
554 parsed_rating = parsed_rating.clamp (1, 5);
555+ } else {
556+ parsed_rating = 0;
557+ }
558
559 parsed_search_string = Search.get_valid_search_string (search);
560 }
561
562=== modified file 'plugins/CMakeLists.txt'
563--- plugins/CMakeLists.txt 2014-06-16 14:04:06 +0000
564+++ plugins/CMakeLists.txt 2015-08-27 10:21:27 +0000
565@@ -12,7 +12,6 @@
566 add_subdirectory (Devices)
567 add_subdirectory (LastFM)
568 add_subdirectory (MPRIS)
569- add_subdirectory (Zeitgeist)
570 else ()
571 message ("-- Plugins disabled")
572 endif ()
573
574=== modified file 'plugins/Devices/AudioPlayers/AudioPlayerDevice.vala'
575--- plugins/Devices/AudioPlayers/AudioPlayerDevice.vala 2015-02-24 00:04:03 +0000
576+++ plugins/Devices/AudioPlayers/AudioPlayerDevice.vala 2015-08-27 10:21:27 +0000
577@@ -24,31 +24,20 @@
578
579 Mount mount;
580 GLib.Icon icon;
581- Noise.DevicePreferences pref;
582 bool is_androphone = false;
583 Gee.LinkedList<string> music_folders;
584-
585+
586 private AudioPlayerLibrary library;
587-
588-
589+
590 public AudioPlayerDevice(Mount mount, bool is_androphone) {
591 this.mount = mount;
592 this.is_androphone = is_androphone;
593 music_folders = new Gee.LinkedList<string> ();
594 library = new AudioPlayerLibrary (this);
595 libraries_manager.add_library (library);
596- icon = new Icon (is_androphone ? "phone" : "music-player").gicon;
597- var device_manager = DeviceManager.get_default ();
598- pref = device_manager.get_device_preferences (get_unique_identifier());
599- if(pref == null) {
600- pref = new Noise.DevicePreferences (get_unique_identifier());
601- device_manager.add_device_preferences (pref);
602- }
603- }
604-
605- public Noise.DevicePreferences get_preferences() {
606- return pref;
607- }
608+ icon = new GLib.ThemedIcon (is_androphone ? "phone" : "music-player");
609+ }
610+
611 public void finish_initialization() {
612 device_unmounted.connect( () => {
613
614@@ -231,7 +220,7 @@
615 }
616
617 public void synchronize () {
618- library.sync_medias ();
619+
620 }
621
622 public bool only_use_custom_view () {
623
624=== modified file 'plugins/Devices/AudioPlayers/AudioPlayerLibrary.vala'
625--- plugins/Devices/AudioPlayers/AudioPlayerLibrary.vala 2015-02-24 00:04:03 +0000
626+++ plugins/Devices/AudioPlayers/AudioPlayerLibrary.vala 2015-08-27 10:21:27 +0000
627@@ -110,7 +110,7 @@
628 return;
629 }
630
631- int parsed_rating;
632+ uint parsed_rating;
633 string parsed_search_string;
634 String.base_search_method (search, out parsed_rating, out parsed_search_string);
635 bool rating_search = parsed_rating > 0;
636@@ -118,7 +118,7 @@
637 lock (medias) {
638 foreach (var m in medias) {
639 if (rating_search) {
640- if (m.rating == (uint) parsed_rating)
641+ if (m.rating == parsed_rating)
642 searched_medias.add (m);
643 } else if (Search.match_string_to_media (m, parsed_search_string)) {
644 searched_medias.add (m);
645@@ -185,96 +185,8 @@
646 }
647 return;
648 }
649-
650- public void sync_medias () {
651- if(doing_file_operations ()) {
652- warning("Tried to add when already syncing\n");
653- return;
654- }
655- Playlist playlist = null;
656- if (device.get_preferences().sync_all_music == false) {
657- playlist = device.get_preferences().music_playlist;
658- if (playlist == null)
659- return;
660- }
661-
662-
663- libraries_manager.current_operation = _("Syncing <b>%s</b>…").printf (device.getDisplayName ());
664-
665- is_doing_file_operations = true;
666- Timeout.add(500, libraries_manager.do_progress_notification_with_timeout);
667- if (playlist == null)
668- sync_medias_async.begin (libraries_manager.local_library.get_medias ());
669- else
670- sync_medias_async.begin (playlist.medias);
671- return;
672- }
673-
674- public async void sync_medias_async (Gee.Collection<Noise.Media> songs) {
675- var medias_to_remove = new Gee.LinkedList<Noise.Media> ();
676- medias_to_remove.add_all (device.delete_doubles (medias, songs));
677-
678- var medias_to_sync = new Gee.LinkedList<Noise.Media> ();
679- medias_to_sync.add_all (device.delete_doubles (songs, medias));
680-
681- int total_medias = medias_to_remove.size + medias_to_sync.size;
682-
683- int sub_index = 0;
684- if (total_medias > 0) {
685- if (device.will_fit_without (medias_to_sync, medias_to_remove)) {
686- foreach(var m in medias_to_remove) {
687- if(!operation_cancelled) {
688- remove_media(m, true);
689- }
690- ++sub_index;
691- libraries_manager.progress = (double)(sub_index/total_medias);
692- }
693- sub_index = 0;
694- imported_files = new Gee.LinkedList<string> ();
695- foreach(var m in medias_to_sync) {
696- if(!operation_cancelled) {
697- add_media (m);
698- }
699- ++sub_index;
700- libraries_manager.progress = (double)(sub_index/total_medias);
701- }
702- tagger.discoverer_import_media (imported_files);
703-
704- if(!operation_cancelled) {
705- // sync playlists
706- /* TODO: add support for podcasts & playlists
707- if (pref.sync_all_music == true) {
708- sync_playlists();
709- }
710- if (pref.sync_all_podcasts == true) {
711- sync_podcasts();
712- }*/
713-
714- libraries_manager.current_operation = _("Finishing sync process…");
715-
716- } else {
717- libraries_manager.current_operation = _("Cancelling Sync…");
718- libraries_manager.progress = 1;
719- }
720- } else {
721- device.infobar_message (_("There is not enough space on Device to complete the Sync…"), Gtk.MessageType.INFO);
722- libraries_manager.current_operation = _("There is not enough space on Device to complete the Sync…");
723- }
724- }
725
726- Idle.add( () => {
727- libraries_manager.progress = 1;
728- device.get_preferences().last_sync_time = (int)time_t();
729- is_doing_file_operations = false;
730-
731- file_operations_done ();
732- operation_cancelled = false;
733-
734- return false;
735- });
736- }
737-
738- public override Media? media_from_id (int id) {
739+ public override Media? media_from_id (int64 id) {
740 lock (medias) {
741 foreach (var m in medias) {
742 if (m.rowid == id) {
743@@ -284,7 +196,8 @@
744 }
745 return null;
746 }
747- public override Gee.Collection<Media> medias_from_ids (Gee.Collection<int> ids) {
748+
749+ public override Gee.Collection<Media> medias_from_ids (Gee.Collection<int64?> ids) {
750 var media_collection = new Gee.LinkedList<Media> ();
751
752 lock (medias) {
753@@ -406,10 +319,10 @@
754 public override void add_smart_playlist (SmartPlaylist p) {
755
756 }
757- public override void remove_smart_playlist (int id) {
758+ public override void remove_smart_playlist (int64 id) {
759
760 }
761- public override SmartPlaylist? smart_playlist_from_id (int id) {
762+ public override SmartPlaylist? smart_playlist_from_id (int64 id) {
763 return null;
764 }
765 public override SmartPlaylist? smart_playlist_from_name (string name) {
766@@ -429,14 +342,18 @@
767 p.media_removed.connect(() => {keep_playlist_synchronized (p);});
768 p.updated.connect ((old_name) => {remove_playlist_from_name (old_name); keep_playlist_synchronized (p);});
769 }
770- public override void remove_playlist (int id) {
771+ public override void remove_playlist (int64 id) {
772 if (id < get_playlists ().size) {
773 var array_v = new Gee.ArrayList<StaticPlaylist> ();
774 array_v.add_all (playlists);
775- var p = array_v.get (id);
776- remove_playlist_from_name (p.name);
777- playlist_removed (p);
778- playlists.remove (p);
779+ foreach (var p in array_v) {
780+ if (p.rowid == id) {
781+ remove_playlist_from_name (p.name);
782+ playlist_removed (p);
783+ playlists.remove (p);
784+ return;
785+ }
786+ }
787 }
788 }
789
790@@ -475,11 +392,14 @@
791 }
792 }
793
794- public override StaticPlaylist? playlist_from_id (int id) {
795+ public override StaticPlaylist? playlist_from_id (int64 id) {
796 if (id < get_playlists ().size) {
797 var array = new Gee.ArrayList<StaticPlaylist> ();
798 array.add_all (get_playlists ());
799- return array.get (id);
800+ foreach (var playlist in array) {
801+ if (playlist.rowid == id)
802+ return playlist;
803+ }
804 }
805 return null;
806 }
807
808=== modified file 'plugins/Devices/CDRom/CDRomDevice.vala'
809--- plugins/Devices/CDRom/CDRomDevice.vala 2015-06-12 13:31:55 +0000
810+++ plugins/Devices/CDRom/CDRomDevice.vala 2015-08-27 10:21:27 +0000
811@@ -48,7 +48,7 @@
812
813 public CDRomDevice(Mount mount) {
814 this.mount = mount;
815- this.icon = new Icon ("media-cdrom-audio").gicon;
816+ this.icon = new GLib.ThemedIcon ("media-cdrom-audio");
817 this.display_name = mount.get_name();
818
819 list = new Gee.LinkedList<Noise.Media>();
820@@ -58,11 +58,7 @@
821 cdplayer = new CDPlayer (mount);
822 Noise.App.player.add_playback (cdplayer);
823 }
824-
825- public Noise.DevicePreferences get_preferences() {
826- return new Noise.DevicePreferences(get_unique_identifier());
827- }
828-
829+
830 public bool start_initialization() {
831 return true;
832 }
833
834=== modified file 'plugins/Devices/CDRom/CDViewWrapper.vala'
835--- plugins/Devices/CDRom/CDViewWrapper.vala 2015-06-12 16:10:33 +0000
836+++ plugins/Devices/CDRom/CDViewWrapper.vala 2015-08-27 10:21:27 +0000
837@@ -28,7 +28,7 @@
838
839 public CDViewWrapper (Noise.StaticPlaylist p) {
840 base (ViewWrapper.Hint.READ_ONLY_PLAYLIST, libraries_manager.local_library);
841- tvs = new TreeViewSetup(ListColumn.NUMBER, Gtk.SortType.ASCENDING, ViewWrapper.Hint.ALBUM_LIST);
842+ tvs = new TreeViewSetup (ViewWrapper.Hint.PLAYLIST);
843 message_head = _("An Error Occured");
844 message_body = _("There was an error while loading this Audio CD.");
845 message_type = Gtk.MessageType.ERROR;
846
847=== modified file 'plugins/Devices/iPod/iPodDevice.vala'
848--- plugins/Devices/iPod/iPodDevice.vala 2015-02-24 00:04:03 +0000
849+++ plugins/Devices/iPod/iPodDevice.vala 2015-08-27 10:21:27 +0000
850@@ -21,7 +21,6 @@
851 */
852
853 public class Noise.Plugins.iPodDevice : GLib.Object, Noise.Device {
854- Noise.DevicePreferences pref;
855 GPod.iTunesDB db;
856 public Mount mount;
857 GLib.Icon icon;
858@@ -32,17 +31,7 @@
859 public iPodDevice (Mount mount) {
860 this.mount = mount;
861 is_new = mount.get_default_location ().get_parse_name ().has_prefix ("afc://");
862- var device_manager = DeviceManager.get_default ();
863- pref = device_manager.get_device_preferences (get_unique_identifier ());
864- icon = new Icon (is_new ? "phone" : "multimedia-player").gicon;
865- if (pref == null) {
866- pref = new Noise.DevicePreferences (get_unique_identifier ());
867- device_manager.add_device_preferences (pref);
868- }
869- }
870-
871- public Noise.DevicePreferences get_preferences () {
872- return pref;
873+ icon = new GLib.ThemedIcon (is_new ? "phone" : "multimedia-player");
874 }
875
876 public bool start_initialization () {
877
878=== modified file 'plugins/Devices/iPod/iPodLibrary.vala'
879--- plugins/Devices/iPod/iPodLibrary.vala 2015-03-13 18:01:49 +0000
880+++ plugins/Devices/iPod/iPodLibrary.vala 2015-08-27 10:21:27 +0000
881@@ -96,7 +96,7 @@
882 return;
883 }
884
885- int parsed_rating;
886+ uint parsed_rating;
887 string parsed_search_string;
888 String.base_search_method (search, out parsed_rating, out parsed_search_string);
889 bool rating_search = parsed_rating > 0;
890@@ -104,7 +104,7 @@
891 lock (medias) {
892 foreach (var m in medias.values) {
893 if (rating_search) {
894- if (m.rating == (uint) parsed_rating)
895+ if (m.rating == parsed_rating)
896 searched_medias.add (m);
897 } else if (Search.match_string_to_media (m, parsed_search_string)) {
898 searched_medias.add (m);
899@@ -242,11 +242,11 @@
900 });
901 }
902
903- public override Media? media_from_id (int id) {
904+ public override Media? media_from_id (int64 id) {
905 return null;
906 }
907
908- public override Gee.Collection<Media> medias_from_ids (Gee.Collection<int> ids) {
909+ public override Gee.Collection<Media> medias_from_ids (Gee.Collection<int64?> ids) {
910 var media_collection = new Gee.LinkedList<Media> ();
911 lock (medias) {
912 foreach (var m in medias.values) {
913@@ -406,11 +406,11 @@
914 return false;
915 }
916
917- public override void remove_smart_playlist (int id) {
918+ public override void remove_smart_playlist (int64 id) {
919
920 }
921
922- public override SmartPlaylist? smart_playlist_from_id (int id) {
923+ public override SmartPlaylist? smart_playlist_from_id (int64 id) {
924 return null;
925 }
926
927@@ -439,24 +439,27 @@
928 p.media_removed.connect((list) => {keep_playlist_synchronized (p, list, false);});
929 }
930
931- public override void remove_playlist (int id) {
932- if (id < get_playlists ().size) {
933- var array = new Gee.ArrayList<unowned GPod.Playlist> ();
934- array.add_all (playlists.keys);
935- var array_v = new Gee.ArrayList<StaticPlaylist> ();
936- array_v.add_all (playlists.values);
937- playlist_removed (array_v.get (id));
938- playlists.unset (array.get (id));
939- db.start_sync ();
940- array.get (id).remove ();
941- try {
942- db.write ();
943- } catch (Error err) {
944- critical ("Error when writing iPod database. iPod contents may be incorrect: %s", err.message);
945+ public override void remove_playlist (int64 id) {
946+ unowned GPod.Playlist to_unset = null;
947+ foreach (var entry in playlists.entries) {
948+ if (entry.value.rowid == id) {
949+ playlist_removed (entry.value);
950+ to_unset = entry.key;
951 }
952-
953- db.stop_sync ();
954- }
955+ }
956+
957+ if (to_unset != null)
958+ playlists.unset (to_unset);
959+
960+ db.start_sync ();
961+ to_unset.remove ();
962+ try {
963+ db.write ();
964+ } catch (Error err) {
965+ critical ("Error when writing iPod database. iPod contents may be incorrect: %s", err.message);
966+ }
967+
968+ db.stop_sync ();
969 }
970
971 private void keep_playlist_synchronized (StaticPlaylist p, Gee.Collection<Media> m, bool to_add) {
972@@ -488,12 +491,13 @@
973 db.stop_sync ();
974 }
975
976- public override StaticPlaylist? playlist_from_id (int id) {
977- if (id < get_playlists ().size) {
978- var array = new Gee.ArrayList<StaticPlaylist> ();
979- array.add_all (get_playlists ());
980- return array.get (id);
981+ public override StaticPlaylist? playlist_from_id (int64 id) {
982+ foreach (var p in playlists.values) {
983+ if (p.rowid == id) {
984+ return p;
985+ }
986 }
987+
988 return null;
989 }
990
991@@ -562,157 +566,6 @@
992 }
993 }
994
995- public bool sync_medias (Gee.Collection<Noise.Media> medias) {
996- if (is_doing_file_operations) {
997- warning("Tried to sync when already syncing\n");
998- return false;
999- }
1000-
1001- libraries_manager.current_operation = _("Syncing <b>%s</b>…").printf (device.getDisplayName ());
1002- is_doing_file_operations = true;
1003- Timeout.add(500, libraries_manager.do_progress_notification_with_timeout);
1004- sync_medias_async.begin (medias);
1005- return true;
1006- }
1007-
1008- public async void sync_medias_async (Gee.Collection<Noise.Media> given_medias) {
1009- bool error_occurred = false;
1010- int sub_index = 0;
1011- debug ("Found %d medias to sync.", given_medias.size);
1012- var medias_to_remove = device.delete_doubles (medias.values, given_medias);
1013- debug ("Found %d medias to remove.", medias_to_remove.size);
1014- var medias_to_sync = device.delete_doubles (given_medias, medias.values);
1015- debug ("Found %d medias to add.", medias_to_sync.size);
1016- int total_medias = medias_to_remove.size + medias_to_sync.size;
1017- if (total_medias > 0) {
1018- if (device.will_fit_without(medias_to_sync, medias_to_remove)) {
1019- db.start_sync();
1020- foreach (var m in medias_to_remove) {
1021- if (!operation_cancelled) {
1022- foreach (var e in medias.entries) {
1023- if (e.value == m) {
1024- remove_media_from_ipod (e.key);
1025- break;
1026- }
1027- }
1028- }
1029-
1030- ++sub_index;
1031- libraries_manager.progress = (double)(sub_index/total_medias);
1032- }
1033-
1034- foreach (var m in medias_to_sync) {
1035- if (!operation_cancelled) {
1036- add_media (m);
1037- }
1038-
1039- ++sub_index;
1040- libraries_manager.progress = (double)(sub_index/total_medias);
1041- }
1042-
1043- if (!operation_cancelled) {
1044- // sync playlists
1045- /* TODO: add support for podcasts & playlists
1046- if (pref.sync_all_music == true) {
1047- sync_playlists();
1048- }
1049- if (pref.sync_all_podcasts == true) {
1050- sync_podcasts();
1051- }*/
1052-
1053- libraries_manager.current_operation = _("Finishing sync process…");
1054- try {
1055- db.write ();
1056- } catch (GLib.Error err) {
1057- error_occurred = true;
1058- operation_cancelled = true;
1059- }
1060-
1061- /// Clean up unused files
1062- debug ("Cleaning up iPod File System\n");
1063- var music_folder = File.new_for_uri (device.get_uri () + GPod.Device.get_music_dir (device.get_mount ().get_default_location ().get_path ()).replace (device.get_mount ().get_default_location ().get_path (), ""));
1064- var used_paths = new Gee.LinkedList<string> ();
1065- foreach (unowned GPod.Track t in medias.keys) {
1066- used_paths.add (device.get_uri () + GPod.iTunesDB.filename_ipod2fs (t.ipod_path));
1067- }
1068-
1069- cleanup_files (music_folder, used_paths);
1070- libraries_manager.progress = 1;
1071- db.stop_sync ();
1072- } else {
1073- libraries_manager.current_operation = _("Cancelling Sync…");
1074- try {
1075- db.write ();
1076- } catch (Error err) {
1077- critical ("Error when writing iPod database. iPod contents may be incorrect: %s", err.message);
1078- }
1079- db.stop_sync ();
1080- libraries_manager.progress = 1;
1081- }
1082- } else {
1083- device.infobar_message (_("There is not enough space on Device to complete the Sync…"), Gtk.MessageType.INFO);
1084- libraries_manager.current_operation = _("There is not enough space on Device to complete the Sync…");
1085- }
1086- }
1087-
1088- Idle.add (() => {
1089- libraries_manager.progress = 1;
1090- device.get_preferences ().last_sync_time = (int)time_t ();
1091- is_doing_file_operations = false;
1092- file_operations_done ();
1093- operation_cancelled = false;
1094- return false;
1095- });
1096- }
1097-
1098- public async void sync_playlists_async (Gee.Collection<Noise.Playlist> spls) {
1099-
1100- /*current_operation = _("Syncing playlists");
1101- // first remove all playlists from db
1102- var all_playlists = new Gee.LinkedList<unowned GPod.Playlist>();
1103- foreach (unowned GPod.Playlist p in db.playlists) {
1104- if (!p.is_mpl() && !p.is_podcasts() && !p.is_audiobooks()) {
1105- all_playlists.add(p);
1106- }
1107- }
1108- foreach (unowned GPod.Playlist p in all_playlists) {
1109- p.remove();
1110- }
1111-
1112- int sub_index = 0;
1113- foreach (var playlist in pls) {
1114- GPod.Playlist p = iPodPlaylistHelper.get_gpod_playlist_from_playlist (playlist);
1115- db.playlist_add((owned)p, -1);
1116-
1117- unowned GPod.Playlist added = db.playlists.nth_data(db.playlists.length() - 1);
1118- foreach (var entry in medias.entries) {
1119- foreach (var e in playlist.medias) {
1120- if (entry.value == e) {
1121- added.add_track(entry.key, -1);
1122- ++sub_index;
1123- //index = (int)(78.0 + (double)(7.0 * (double)((double)sub_index/(double)pls.size)));
1124- break;
1125- }
1126- }
1127- }
1128- }
1129-
1130- foreach (var smart_playlist in spls) {
1131- GPod.Playlist p = iPodPlaylistHelper.get_gpod_playlist_from_smart_playlist (smart_playlist);
1132-
1133- db.playlist_add((owned)p, -1);
1134-
1135- ++sub_index;
1136- //index = (int)(85.0 + (double)(5.0 * (double)((double)sub_index/(double)spls.size)));
1137- }
1138- db.spl_update_live();
1139-
1140- Idle.add( () => {
1141-
1142- return false;
1143- });*/
1144- }
1145-
1146 void cleanup_files(GLib.File music_folder, Gee.LinkedList<string> used_uris) {
1147 GLib.FileInfo file_info = null;
1148 try {
1149
1150=== modified file 'plugins/Devices/iPod/iPodPlaylistHelper.vala'
1151--- plugins/Devices/iPod/iPodPlaylistHelper.vala 2015-02-26 16:44:26 +0000
1152+++ plugins/Devices/iPod/iPodPlaylistHelper.vala 2015-08-27 10:21:27 +0000
1153@@ -115,59 +115,57 @@
1154 message("adding rule\n");
1155 if (q.field == SmartQuery.FieldType.ALBUM) { // strings
1156 rule.field = GPod.SPLField.ALBUM;
1157- rule.@string = q.value;
1158+ rule.@string = q.value.get_string ();
1159 } else if (q.field == SmartQuery.FieldType.ARTIST) {
1160 rule.field = GPod.SPLField.ARTIST;
1161- rule.@string = q.value;
1162+ rule.@string = q.value.get_string ();
1163 } else if (q.field == SmartQuery.FieldType.COMPOSER) {
1164 rule.field = GPod.SPLField.COMPOSER;
1165- rule.@string = q.value;
1166+ rule.@string = q.value.get_string ();
1167 } else if (q.field == SmartQuery.FieldType.COMMENT) {
1168 rule.field = GPod.SPLField.COMMENT;
1169- rule.@string = q.value;
1170+ rule.@string = q.value.get_string ();
1171 } else if (q.field == SmartQuery.FieldType.GENRE) {
1172 rule.field = GPod.SPLField.GENRE;
1173- rule.@string = q.value;
1174+ rule.@string = q.value.get_string ();
1175 } else if (q.field == SmartQuery.FieldType.GROUPING) {
1176 rule.field = GPod.SPLField.GROUPING;
1177- rule.@string = q.value;
1178+ rule.@string = q.value.get_string ();
1179 } else if (q.field == SmartQuery.FieldType.TITLE) {
1180 rule.field = GPod.SPLField.SONG_NAME;
1181- rule.@string = q.value;
1182+ rule.@string = q.value.get_string ();
1183 } else if (q.field == SmartQuery.FieldType.BITRATE) { // ints
1184 rule.field = GPod.SPLField.BITRATE;
1185- rule.fromvalue = uint64.parse (q.value);
1186- rule.tovalue = uint64.parse (q.value);
1187+ rule.fromvalue = (uint64)q.value.get_int ();
1188+ rule.tovalue = (uint64)q.value.get_int ();
1189 } else if (q.field == SmartQuery.FieldType.PLAYCOUNT) {
1190 rule.field = GPod.SPLField.PLAYCOUNT;
1191- rule.fromvalue = uint64.parse (q.value);
1192- rule.tovalue = uint64.parse (q.value);
1193+ rule.fromvalue =(uint64)q.value.get_int ();
1194+ rule.tovalue = (uint64)q.value.get_int ();
1195 } else if (q.field == SmartQuery.FieldType.SKIPCOUNT) {
1196 rule.field = GPod.SPLField.SKIPCOUNT;
1197- rule.fromvalue = uint64.parse (q.value);
1198- rule.tovalue = uint64.parse (q.value);
1199+ rule.fromvalue = (uint64)q.value.get_int ();
1200+ rule.tovalue = (uint64)q.value.get_int ();
1201 } else if (q.field == SmartQuery.FieldType.YEAR) {
1202 rule.field = GPod.SPLField.YEAR;
1203- rule.fromvalue = uint64.parse (q.value);
1204- rule.tovalue = uint64.parse (q.value);
1205+ rule.fromvalue = (uint64)q.value.get_int ();
1206+ rule.tovalue = (uint64)q.value.get_int ();
1207 } else if (q.field == SmartQuery.FieldType.LENGTH) {
1208 rule.field = GPod.SPLField.TIME;
1209- rule.fromvalue = uint64.parse (q.value) * 1000;
1210- rule.tovalue = uint64.parse (q.value) * 1000;
1211+ rule.fromvalue = (uint64)q.value.get_int () * 1000;
1212+ rule.tovalue = (uint64)q.value.get_int () * 1000;
1213 } else if (q.field == SmartQuery.FieldType.RATING) {
1214 rule.field = GPod.SPLField.RATING;
1215- rule.fromvalue = uint64.parse (q.value) * 20;
1216- rule.tovalue = uint64.parse (q.value) * 20;
1217+ rule.fromvalue = (uint64)q.value.get_int () * 20;
1218+ rule.tovalue = (uint64)q.value.get_int () * 20;
1219 } else if (q.field == SmartQuery.FieldType.DATE_ADDED) {
1220 rule.field = GPod.SPLField.DATE_ADDED;
1221- rule.fromvalue = uint64.parse (q.value) * 1000;
1222- rule.tovalue = uint64.parse (q.value) * 1000;
1223+ rule.fromvalue = (uint64)q.value.get_int () * 1000;
1224+ rule.tovalue = (uint64)q.value.get_int () * 1000;
1225 } else if (q.field == SmartQuery.FieldType.LAST_PLAYED) {
1226 rule.field = GPod.SPLField.LAST_PLAYED;
1227- rule.fromvalue = uint64.parse (q.value) * 20;
1228- rule.tovalue = uint64.parse (q.value) * 20;
1229- } else if (q.field == SmartQuery.FieldType.DATE_RELEASED) {
1230- // no equivalant
1231+ rule.fromvalue = (uint64)q.value.get_int () * 20;
1232+ rule.tovalue = (uint64)q.value.get_int () * 20;
1233 }
1234 /*
1235 else if (q.field == SmartQuery.FieldType.MEDIA_TYPE) {
1236@@ -220,108 +218,88 @@
1237 switch (field) {
1238 case SmartQuery.FieldType.ALBUM:
1239 rule.field = GPod.SPLField.ALBUM;
1240- rule.@string = value;
1241+ rule.@string = value.get_string ();
1242 break;
1243 case SmartQuery.FieldType.ARTIST:
1244 rule.field = GPod.SPLField.ARTIST;
1245- rule.@string = value;
1246+ rule.@string = value.get_string ();
1247 break;
1248 case SmartQuery.FieldType.COMPOSER:
1249 rule.field = GPod.SPLField.COMPOSER;
1250- rule.@string = value;
1251+ rule.@string = value.get_string ();
1252 break;
1253 case SmartQuery.FieldType.COMMENT:
1254 rule.field = GPod.SPLField.COMMENT;
1255- rule.@string = value;
1256+ rule.@string = value.get_string ();
1257 break;
1258 case SmartQuery.FieldType.GENRE:
1259 rule.field = GPod.SPLField.GENRE;
1260- rule.@string = value;
1261+ rule.@string = value.get_string ();
1262 break;
1263 case SmartQuery.FieldType.GROUPING:
1264 rule.field = GPod.SPLField.GROUPING;
1265- rule.@string = value;
1266+ rule.@string = value.get_string ();
1267 break;
1268 case SmartQuery.FieldType.TITLE:
1269 rule.field = GPod.SPLField.SONG_NAME;
1270- rule.@string = value;
1271+ rule.@string = value.get_string ();
1272 break;
1273 case SmartQuery.FieldType.BITRATE:
1274 rule.field = GPod.SPLField.BITRATE;
1275- rule.fromvalue = uint64.parse (value);
1276- rule.tovalue = uint64.parse (value);
1277+ rule.fromvalue = (uint64)value.get_int ();
1278+ rule.tovalue = (uint64)value.get_int ();
1279 rule.tounits = 1;
1280 rule.fromunits = 1;
1281 break;
1282 case SmartQuery.FieldType.PLAYCOUNT:
1283 rule.field = GPod.SPLField.PLAYCOUNT;
1284- rule.fromvalue = uint64.parse (value);
1285- rule.tovalue = uint64.parse (value);
1286+ rule.fromvalue = (uint64)value.get_int ();
1287+ rule.tovalue = (uint64)value.get_int ();
1288 rule.tounits = 1;
1289 rule.fromunits = 1;
1290 break;
1291 case SmartQuery.FieldType.SKIPCOUNT:
1292 rule.field = GPod.SPLField.SKIPCOUNT;
1293- rule.fromvalue = uint64.parse (value);
1294- rule.tovalue = uint64.parse (value);
1295+ rule.fromvalue = (uint64)value.get_int ();
1296+ rule.tovalue = (uint64)value.get_int ();
1297 rule.tounits = 1;
1298 break;
1299 case SmartQuery.FieldType.YEAR:
1300 rule.field = GPod.SPLField.YEAR;
1301- rule.fromvalue = uint64.parse (value);
1302- rule.tovalue = uint64.parse (value);
1303+ rule.fromvalue = (uint64)value.get_int ();
1304+ rule.tovalue = (uint64)value.get_int ();
1305 rule.tounits = 1;
1306 rule.fromunits = 1;
1307 break;
1308 case SmartQuery.FieldType.LENGTH:
1309 rule.field = GPod.SPLField.TIME;
1310- rule.fromvalue = uint64.parse (value) * 1000;
1311- rule.tovalue = uint64.parse (value) * 1000;
1312+ rule.fromvalue = (uint64)value.get_int () * 1000;
1313+ rule.tovalue = (uint64)value.get_int () * 1000;
1314 rule.tounits = 1;
1315 rule.fromunits = 1;
1316 break;
1317 case SmartQuery.FieldType.RATING:
1318- message("rating rule is %s\n", value);
1319+ message("rating rule is %d\n", value.get_int ());
1320 rule.field = GPod.SPLField.RATING;
1321- rule.fromvalue = uint64.parse (value) * 20;
1322- rule.tovalue = uint64.parse (value) * 20;
1323+ rule.fromvalue = (uint64)value.get_int () * 20;
1324+ rule.tovalue = (uint64)value.get_int () * 20;
1325 rule.tounits = 1;//20;
1326 rule.fromunits = 1;//20;
1327 break;
1328 case SmartQuery.FieldType.DATE_ADDED:
1329 rule.field = GPod.SPLField.DATE_ADDED;
1330- rule.fromvalue = uint64.parse (value) * 60 * 60 * 24;
1331- rule.tovalue = uint64.parse (value) * 60 * 60 * 24;
1332+ rule.fromvalue = (uint64)value.get_int () * 60 * 60 * 24;
1333+ rule.tovalue = (uint64)value.get_int () * 60 * 60 * 24;
1334 rule.tounits = 1;//60 * 60 * 24;
1335 rule.fromunits = 1;//60 * 60 * 24;
1336 break;
1337 case SmartQuery.FieldType.LAST_PLAYED:
1338 rule.field = GPod.SPLField.LAST_PLAYED;
1339- rule.fromvalue = uint64.parse (value) * 60 * 60 * 24;
1340- rule.tovalue = uint64.parse (value) * 60 * 60 * 24;
1341+ rule.fromvalue = (uint64)value.get_int () * 60 * 60 * 24;
1342+ rule.tovalue = (uint64)value.get_int () * 60 * 60 * 24;
1343 rule.tounits = 1;//60 * 60 * 24;
1344 rule.fromunits = 1;//60 * 60 * 24;
1345 break;
1346- case SmartQuery.FieldType.DATE_RELEASED:
1347- // no equivelant
1348- break;
1349-/*
1350- case SmartQuery.FieldType.MEDIA_TYPE:
1351- rule.field = GPod.SPLField.VIDEO_KIND;
1352- if (value == "0") {
1353- message ("must be song\n");
1354- rule.fromvalue = 0x00000001;
1355- rule.tovalue = 0x00000001;;
1356- } else if (value == "1") {
1357- rule.fromvalue = 0x00000006;
1358- rule.tovalue = 0x00000006;
1359- message ("must be podcast\n");
1360- } else if (value == "2") {
1361- rule.fromvalue = 0x00000008;
1362- rule.tovalue = 0x00000008;
1363- }
1364- break;
1365-*/
1366 }
1367
1368 // set action type
1369
1370=== modified file 'plugins/LastFM/Core.vala'
1371--- plugins/LastFM/Core.vala 2015-05-07 22:46:59 +0000
1372+++ plugins/LastFM/Core.vala 2015-08-27 10:21:27 +0000
1373@@ -45,11 +45,15 @@
1374 return core;
1375 }
1376
1377+ private GLib.Cancellable fetch_cancellable;
1378+
1379 private Core () {
1380- similarMedias = new LastFM.SimilarMedias();
1381+ fetch_cancellable = new GLib.Cancellable ();
1382+ similarMedias = new LastFM.SimilarMedias ();
1383 Noise.App.main_window.update_media_info.connect ((media) => {postNowPlaying (media);});
1384 Noise.App.main_window.media_half_played.connect ((media) => {postScrobbleTrack (media);});
1385 Noise.libraries_manager.local_library.media_imported.connect ((medias) => {fetch_albums_slowly.begin (medias);});
1386+ Noise.NotificationManager.get_default ().search_cover.connect ((m) => { get_album_infos.begin (m, fetch_cancellable);});
1387 similarMedias.similar_retrieved.connect(similar_retrieved_signal);
1388 }
1389
1390@@ -126,22 +130,11 @@
1391 albums.add (album_s);
1392 if (!album_artist.contains (album_artist_s))
1393 album_artist.add (album_artist_s);
1394- fetch_album_info (media);
1395+ get_album_infos.begin (media, fetch_cancellable);
1396 }
1397 }
1398 }
1399
1400- public void fetch_album_info (Noise.Media media) {
1401- try {
1402- new Thread<void*>.try (null, () => {
1403- get_album_infos (media);
1404- return null;
1405- });
1406- } catch (GLib.Error err) {
1407- warning ("ERROR: Could not create thread to have fun: %s", err.message);
1408- }
1409- }
1410-
1411 /** Update's the user's currently playing track on last.fm
1412 *
1413 */
1414@@ -188,7 +181,7 @@
1415 }
1416
1417 public void fetchCurrentSimilarSongs () {
1418- similarMedias.queryForSimilar (Noise.App.player.current_media);
1419+ similarMedias.query_for_similar (Noise.App.player.current_media);
1420 }
1421
1422 private void similar_retrieved_signal (Gee.LinkedList<int> similarIDs, Gee.LinkedList<Noise.Media> similarDont) {
1423@@ -201,7 +194,7 @@
1424 * @param title The title of media to get similar to
1425 * @return The media that are similar
1426 */
1427- public Gee.TreeSet<Noise.Media> getSimilarTracks(string title, string artist) {
1428+ public async Gee.TreeSet<Noise.Media> get_similar_tracks (string title, string artist, GLib.Cancellable cancellable) {
1429 var returned_medias = new Gee.TreeSet<Noise.Media> ();
1430
1431 var uri = new Soup.URI (API_URL);
1432@@ -211,38 +204,42 @@
1433 "track", title,
1434 "format", "json");
1435 var session = new Soup.Session ();
1436- var uri_request = session.request_uri (uri);
1437-
1438- /* send the HTTP request */
1439- var stream = uri_request.send ();
1440- var parser = new Json.Parser ();
1441- parser.load_from_stream (stream);
1442- weak Json.Object parser_object = parser.get_root ().get_object ();
1443- if (parser_object == null || parser_object.has_member ("similartracks") == false)
1444- return returned_medias;
1445-
1446- weak Json.Object similartracks = parser_object.get_object_member ("similartracks");
1447- if (similartracks.has_member ("track") && similartracks.get_member ("track").get_node_type () == Json.NodeType.ARRAY) {
1448- List<unowned Json.Node> similar_tracks_values = similartracks.get_array_member ("track").get_elements ();
1449- foreach (unowned Json.Node element in similar_tracks_values) {
1450- weak Json.Object track_object = element.get_object ();
1451- var similar_to_add = new Noise.Media ("");
1452- returned_medias.add (similar_to_add);
1453- similar_to_add.title = track_object.get_string_member ("name");
1454- if (track_object.has_member ("url"))
1455- similar_to_add.comment = track_object.get_string_member ("url");
1456- if (track_object.has_member ("artist")) {
1457- weak Json.Object artist_object = track_object.get_object_member ("artist");
1458- if (artist_object.has_member ("name"))
1459- similar_to_add.artist = artist_object.get_string_member ("name");
1460+ try {
1461+ var uri_request = session.request_uri (uri);
1462+
1463+ /* send the HTTP request */
1464+ var stream = yield uri_request.send_async (cancellable);
1465+ var parser = new Json.Parser ();
1466+ parser.load_from_stream (stream);
1467+ weak Json.Object parser_object = parser.get_root ().get_object ();
1468+ if (parser_object == null || parser_object.has_member ("similartracks") == false)
1469+ return returned_medias;
1470+
1471+ weak Json.Object similartracks = parser_object.get_object_member ("similartracks");
1472+ if (similartracks.has_member ("track") && similartracks.get_member ("track").get_node_type () == Json.NodeType.ARRAY) {
1473+ List<unowned Json.Node> similar_tracks_values = similartracks.get_array_member ("track").get_elements ();
1474+ foreach (unowned Json.Node element in similar_tracks_values) {
1475+ weak Json.Object track_object = element.get_object ();
1476+ var similar_to_add = new Noise.Media ("");
1477+ returned_medias.add (similar_to_add);
1478+ similar_to_add.title = track_object.get_string_member ("name");
1479+ if (track_object.has_member ("url"))
1480+ similar_to_add.comment = track_object.get_string_member ("url");
1481+ if (track_object.has_member ("artist")) {
1482+ weak Json.Object artist_object = track_object.get_object_member ("artist");
1483+ if (artist_object.has_member ("name"))
1484+ similar_to_add.artist = artist_object.get_string_member ("name");
1485+ }
1486 }
1487 }
1488+ } catch (Error e) {
1489+ critical (e.message);
1490 }
1491
1492 return returned_medias;
1493 }
1494
1495- public void get_album_infos (Noise.Media m) {
1496+ public async void get_album_infos (Noise.Media m, Cancellable cancellable) {
1497 var uri = new Soup.URI (API_URL);
1498 uri.set_query_from_fields ("method", "album.getinfo",
1499 "api_key", api_key,
1500@@ -250,48 +247,52 @@
1501 "album", m.album,
1502 "format", "json");
1503 var session = new Soup.Session ();
1504- var uri_request = session.request_uri (uri);
1505-
1506- /* send the HTTP request */
1507- var stream = uri_request.send ();
1508- var parser = new Json.Parser ();
1509- parser.load_from_stream (stream);
1510- weak Json.Object parser_object = parser.get_root ().get_object ();
1511- if (parser_object == null || parser_object.has_member ("album") == false)
1512- return;
1513-
1514- weak Json.Object album_object = parser_object.get_member ("album").get_object ();
1515- if (album_object.has_member ("image") && album_object.get_member ("image").get_node_type () == Json.NodeType.ARRAY) {
1516- List<unowned Json.Node> image_values = album_object.get_array_member ("image").get_elements ();
1517- string image_url = "";
1518- string image_size = "";
1519- foreach (unowned Json.Node element in image_values) {
1520- weak Json.Object image_object = element.get_object ();
1521- unowned string new_size = image_object.get_string_member ("size");
1522- if (new_size == "mega" ||
1523- (new_size == "extralarge" && image_size != "mega") ||
1524- (new_size == "large" && image_size != "mega" && image_size != "extralarge")) {
1525- image_url = image_object.get_string_member ("#text").dup ();
1526- image_size = new_size.dup ();
1527- }
1528- }
1529-
1530- var coverart_cache = Noise.CoverartCache.instance;
1531- if (image_url != "" && coverart_cache.has_image (m) == false) {
1532-
1533- debug ("Caching last.fm image from URL: %s", image_url);
1534- var image_file = File.new_for_uri (image_url);
1535- coverart_cache.cache_image_from_file_async.begin (m, image_file);
1536- }
1537- }
1538-
1539- if (album_object.has_member ("releasedate") && m.year == 0) {
1540- var releasedate = album_object.get_string_member ("releasedate");
1541- var date = Date ();
1542- date.set_parse (releasedate);
1543- if (date.valid ()) {
1544- m.year = date.get_year ();
1545- }
1546+ try {
1547+ var uri_request = session.request_uri (uri);
1548+
1549+ /* send the HTTP request */
1550+ var stream = yield uri_request.send_async (cancellable);
1551+ var parser = new Json.Parser ();
1552+ parser.load_from_stream (stream);
1553+ weak Json.Object parser_object = parser.get_root ().get_object ();
1554+ if (parser_object == null || parser_object.has_member ("album") == false)
1555+ return;
1556+
1557+ weak Json.Object album_object = parser_object.get_member ("album").get_object ();
1558+ if (album_object.has_member ("image") && album_object.get_member ("image").get_node_type () == Json.NodeType.ARRAY) {
1559+ List<unowned Json.Node> image_values = album_object.get_array_member ("image").get_elements ();
1560+ string image_url = "";
1561+ string image_size = "";
1562+ foreach (unowned Json.Node element in image_values) {
1563+ weak Json.Object image_object = element.get_object ();
1564+ unowned string new_size = image_object.get_string_member ("size");
1565+ if (new_size == "mega" ||
1566+ (new_size == "extralarge" && image_size != "mega") ||
1567+ (new_size == "large" && image_size != "mega" && image_size != "extralarge")) {
1568+ image_url = image_object.get_string_member ("#text").dup ();
1569+ image_size = new_size.dup ();
1570+ }
1571+ }
1572+
1573+ var coverart_cache = Noise.CoverartCache.instance;
1574+ if (image_url != "" && coverart_cache.has_image (m) == false) {
1575+
1576+ debug ("Caching last.fm image from URL: %s", image_url);
1577+ var image_file = File.new_for_uri (image_url);
1578+ coverart_cache.cache_image_from_file_async.begin (m, image_file);
1579+ }
1580+ }
1581+
1582+ if (album_object.has_member ("releasedate") && m.year == 0) {
1583+ var releasedate = album_object.get_string_member ("releasedate");
1584+ var date = Date ();
1585+ date.set_parse (releasedate);
1586+ if (date.valid ()) {
1587+ m.year = date.get_year ();
1588+ }
1589+ }
1590+ } catch (Error e) {
1591+ critical (e.message);
1592 }
1593 }
1594
1595
1596=== modified file 'plugins/LastFM/LastFM.vala'
1597--- plugins/LastFM/LastFM.vala 2015-06-12 16:10:33 +0000
1598+++ plugins/LastFM/LastFM.vala 2015-08-27 10:21:27 +0000
1599@@ -86,7 +86,7 @@
1600 var core = LastFM.Core.get_default ();
1601 core.initialize (client_id, client_secret, token);
1602 App.main_window.source_list_added.connect (source_list_added);
1603- libraries_manager.local_library.add_playlist (core.get_similar_playlist ());
1604+ libraries_manager.add_headless_playlist (core.get_similar_playlist ());
1605 similar_media_widget = new Noise.SimilarMediasWidget (core);
1606 added_view = true;
1607 } catch (Error e) {
1608
1609=== modified file 'plugins/LastFM/SimilarMedia.vala'
1610--- plugins/LastFM/SimilarMedia.vala 2015-05-07 22:46:59 +0000
1611+++ plugins/LastFM/SimilarMedia.vala 2015-08-27 10:21:27 +0000
1612@@ -26,59 +26,52 @@
1613 public class LastFM.SimilarMedias : Object {
1614 public static const int MAX_FETCHED = 20;
1615
1616- bool working;
1617+ public signal void similar_retrieved (Gee.LinkedList<int64?> similarIDs, Gee.LinkedList<Noise.Media> similarDont);
1618
1619 public Noise.StaticPlaylist similar_playlist;
1620- private Gee.LinkedList<Noise.Media> similar_medias;
1621-
1622- public signal void similar_retrieved (Gee.LinkedList<int> similarIDs, Gee.LinkedList<Noise.Media> similarDont);
1623+ private GLib.Cancellable cancellable;
1624
1625 public class SimilarMedias () {
1626- working = false;
1627- similar_medias = new Gee.LinkedList<Noise.Media> ();
1628+ cancellable = new GLib.Cancellable ();
1629 similar_playlist = new Noise.StaticPlaylist ();
1630 similar_playlist.name = _("Similar");
1631 similar_playlist.read_only = true;
1632 similar_playlist.show_badge = true;
1633- try {
1634- similar_playlist.icon = GLib.Icon.new_for_string ("playlist-similar");
1635- } catch (GLib.Error e) {
1636- critical (e.message);
1637- }
1638-
1639+ similar_playlist.icon = new GLib.ThemedIcon ("playlist-similar");
1640+
1641 Noise.App.player.changing_player.connect ((m)=>{
1642- lock (similar_medias) {
1643- similar_medias.clear ();
1644- }
1645 lock (similar_playlist) {
1646 similar_playlist.clear ();
1647 }
1648 });
1649 }
1650-
1651- public virtual void queryForSimilar (Noise.Media s) {
1652-
1653- if (!working) {
1654- working = true;
1655-
1656- similar_async (s);
1657+
1658+ public virtual void query_for_similar (Noise.Media s) {
1659+ if (cancellable.is_cancelled () == false) {
1660+ cancellable.cancel ();
1661 }
1662+
1663+ similar_async.begin (s);
1664 }
1665
1666- public void similar_async (Noise.Media s) {
1667+ public async void similar_async (Noise.Media s) {
1668 debug ("In the similar thread");
1669- var similarIDs = new Gee.LinkedList<int> ();
1670+ cancellable.reset ();
1671+ var similar_medias = yield Core.get_default ().get_similar_tracks (s.title, s.artist, cancellable);
1672+ if (cancellable.is_cancelled ())
1673+ return;
1674+
1675+ var similarIDs = new Gee.LinkedList<int64?> ();
1676 var similarDont = new Gee.LinkedList<Noise.Media> ();
1677-
1678- similar_medias.add_all (Core.get_default ().getSimilarTracks (s.title, s.artist));
1679- lock (similar_medias) {
1680- Noise.libraries_manager.local_library.media_from_name (similar_medias, similarIDs, similarDont);
1681- }
1682+ Noise.libraries_manager.local_library.media_from_name (similar_medias, similarIDs, similarDont);
1683+ if (cancellable.is_cancelled ())
1684+ return;
1685+
1686 similarIDs.offer_head (s.rowid);
1687-
1688- similar_playlist.add_medias (Noise.libraries_manager.local_library.medias_from_ids (similarIDs));
1689+ var found_medias = Noise.libraries_manager.local_library.medias_from_ids (similarIDs);
1690+ found_medias.remove (s);
1691+ similar_playlist.add_medias (found_medias);
1692 similar_retrieved (similarIDs, similarDont);
1693- working = false;
1694 }
1695
1696 }
1697
1698=== modified file 'plugins/LastFM/SimilarMediaWidget.vala'
1699--- plugins/LastFM/SimilarMediaWidget.vala 2015-05-07 22:46:59 +0000
1700+++ plugins/LastFM/SimilarMediaWidget.vala 2015-08-27 10:21:27 +0000
1701@@ -35,14 +35,12 @@
1702 lfm.similar_retrieved.connect (similar_retrieved);
1703
1704 App.main_window.update_media_info.connect ((m) => {
1705- lfm.fetchCurrentSimilarSongs();
1706- lfm.fetch_album_info (m);
1707+ lfm.fetchCurrentSimilarSongs ();
1708 });
1709 App.player.changing_player.connect ((m) => {
1710 similars_fetched = false;
1711 update_visibilities ();
1712 });
1713- NotificationManager.get_default ().search_cover.connect ((m) => { lfm.fetch_album_info (m);});
1714
1715 love_ban_buttons = new LoveBanButtons ();
1716 // put treeview inside scrolled window
1717
1718=== modified file 'plugins/LastFM/noise-lastfm.application'
1719--- plugins/LastFM/noise-lastfm.application 2015-05-07 22:46:59 +0000
1720+++ plugins/LastFM/noise-lastfm.application 2015-08-27 10:21:27 +0000
1721@@ -3,6 +3,11 @@
1722 <description>Music</description>
1723 <desktop-entry>noise.desktop</desktop-entry>
1724 <translations>noise</translations>
1725+ <services>
1726+ <service id="lastfm-scrobble">
1727+ <description>Scrobble all your music</description>
1728+ </service>
1729+ </services>
1730 <service-types>
1731 <service-type id="scrobbling">
1732 </service-type>
1733
1734=== modified file 'plugins/MPRIS/MPRIS.vala'
1735--- plugins/MPRIS/MPRIS.vala 2015-05-24 21:40:48 +0000
1736+++ plugins/MPRIS/MPRIS.vala 2015-08-27 10:21:27 +0000
1737@@ -232,7 +232,7 @@
1738 }
1739
1740 private ObjectPath get_track_id (Noise.Media m) {
1741- return new ObjectPath ("/org/pantheon/noise/Track/%d".printf (m.rowid));
1742+ return new ObjectPath ("/org/pantheon/noise/Track/%lld".printf (m.rowid));
1743 }
1744
1745 private bool send_property_change() {
1746
1747=== removed directory 'plugins/Zeitgeist'
1748=== removed file 'plugins/Zeitgeist/CMakeLists.txt'
1749--- plugins/Zeitgeist/CMakeLists.txt 2014-06-28 19:50:12 +0000
1750+++ plugins/Zeitgeist/CMakeLists.txt 1970-01-01 00:00:00 +0000
1751@@ -1,34 +0,0 @@
1752-pkg_check_modules(ZEITGEIST_DEPS zeitgeist-2.0)
1753-
1754-if (ZEITGEIST_DEPS_FOUND)
1755-
1756-set(DEPS_CFLAGS ${DEPS_CFLAGS} ${ZEITGEIST_DEPS_CFLAGS})
1757-set(DEPS_LIBRARIES ${DEPS_LIBRARIES} ${ZEITGEIST_DEPS_LIBRARIES})
1758-set(DEPS_LIBRARY_DIRS ${DEPS_LIBRARY_DIRS} ${ZEITGEIST_DEPS_LIBRARY_DIRS})
1759-
1760-add_definitions(${DEPS_CFLAGS})
1761-link_directories(${DEPS_LIBRARY_DIRS})
1762-
1763-set(TARGET_NAME zeitgeist)
1764-vala_precompile(ZEITGEIST_VALA_C ${TARGET_NAME}
1765- Zeitgeist.vala
1766-PACKAGES
1767- ${DEPS_PACKAGES}
1768- zeitgeist-2.0
1769-OPTIONS
1770- ${GLOBAL_VALAC_OPTIONS}
1771-)
1772-
1773-add_library(${TARGET_NAME} MODULE ${ZEITGEIST_VALA_C})
1774-
1775-target_link_libraries(${TARGET_NAME} ${DEPS_LIBRARIES})
1776-add_dependencies(${TARGET_NAME} ${SRC_TARGET})
1777-
1778-install(TARGETS ${TARGET_NAME} DESTINATION ${PLUGIN_DIR}/Zeitgeist/)
1779-install(FILES zeitgeist.plugin DESTINATION ${PLUGIN_DIR}/Zeitgeist/)
1780-
1781-else ()
1782-
1783-message("-- Zeitgeist plugin disabled")
1784-
1785-endif ()
1786\ No newline at end of file
1787
1788=== removed file 'plugins/Zeitgeist/Zeitgeist.vala'
1789--- plugins/Zeitgeist/Zeitgeist.vala 2014-07-22 02:49:15 +0000
1790+++ plugins/Zeitgeist/Zeitgeist.vala 1970-01-01 00:00:00 +0000
1791@@ -1,88 +0,0 @@
1792-
1793-namespace Noise.Plugins {
1794-
1795- public class ZeitgeistPlugin : Peas.ExtensionBase, Peas.Activatable {
1796-
1797- public Object object { owned get; construct; }
1798-
1799- Zeitgeist.Log zeitgeist;
1800- PlaybackManager player;
1801-
1802- Media? current_song = null;
1803-
1804- bool connected = false;
1805-
1806- public void activate () {
1807- message ("Activating Zeitgeist plugin");
1808-
1809- zeitgeist = Zeitgeist.Log.get_default ();
1810-
1811- Value value = Value (typeof (Object));
1812- get_property ("object", ref value);
1813- var plugins = (Noise.Plugins.Interface) value.get_object();
1814-
1815- plugins.register_function (Interface.Hook.WINDOW, () => {
1816- connected = true;
1817-
1818- player = Noise.App.player;
1819- player.media_played.connect (media_changed);
1820- });
1821- }
1822-
1823- public void deactivate () {
1824- if (connected)
1825- player.media_played.disconnect (media_changed);
1826-
1827- connected = false;
1828- }
1829-
1830- void media_changed (Media played_media) {
1831- if (current_song != null)
1832- log_interaction.begin (current_song, Zeitgeist.ZG.LEAVE_EVENT);
1833-
1834- log_interaction.begin (played_media, Zeitgeist.ZG.ACCESS_EVENT);
1835- current_song = played_media;
1836- }
1837-
1838- async void log_interaction (Media song, string interpretation) {
1839- var time = new DateTime.now_local ().to_unix () * 1000;
1840-
1841- FileInfo? info = null;
1842- try {
1843- info = yield song.file.query_info_async (FileAttribute.STANDARD_CONTENT_TYPE, 0);
1844- } catch (Error e) {}
1845-
1846- var subject = new Zeitgeist.Subject ();
1847- subject.uri = song.uri;
1848- subject.interpretation = Zeitgeist.NFO.AUDIO;
1849- subject.manifestation = Zeitgeist.NFO.FILE_DATA_OBJECT;
1850- subject.origin = song.get_display_location ();
1851- subject.mimetype = info != null ? info.get_content_type () : null;
1852- subject.text = "%s - %s - %s".printf (song.get_display_title (),
1853- song.get_display_artist (), song.get_display_album ());
1854-
1855- var event = new Zeitgeist.Event ();
1856- event.timestamp = time;
1857- event.interpretation = interpretation;
1858- event.manifestation = Zeitgeist.ZG.USER_ACTIVITY;
1859- event.actor = "application://noise.desktop";
1860- event.add_subject (subject);
1861-
1862- try {
1863- zeitgeist.insert_event_no_reply (event);
1864- } catch (Error e) {
1865- warning ("Logging to zeitgeist failed: %s", e.message);
1866- }
1867- }
1868-
1869- public void update_state () {
1870- }
1871- }
1872-}
1873-
1874-[ModuleInit]
1875-public void peas_register_types (TypeModule module) {
1876- var objmodule = module as Peas.ObjectModule;
1877- objmodule.register_extension_type (typeof (Peas.Activatable),
1878- typeof (Noise.Plugins.ZeitgeistPlugin));
1879-}
1880
1881=== removed file 'plugins/Zeitgeist/zeitgeist.plugin'
1882--- plugins/Zeitgeist/zeitgeist.plugin 2014-06-16 14:04:06 +0000
1883+++ plugins/Zeitgeist/zeitgeist.plugin 1970-01-01 00:00:00 +0000
1884@@ -1,9 +0,0 @@
1885-[Plugin]
1886-Module=zeitgeist
1887-IAge=2
1888-Name=Log to Zeitgeist
1889-Description=Log the played songs to Zeitgeist
1890-Authors=Noise Developers
1891-Copyright=Copyright © 2014 Noise Developers
1892-Website=http://launchpad.net/noise
1893-
1894
1895=== modified file 'schemas/org.pantheon.noise.gschema.xml'
1896--- schemas/org.pantheon.noise.gschema.xml 2014-11-27 19:22:08 +0000
1897+++ schemas/org.pantheon.noise.gschema.xml 2015-08-27 10:21:27 +0000
1898@@ -51,12 +51,12 @@
1899 <summary>List of desktop shells for which the player's window will be minimized instead of hidden when the close-while-playing option is set to false.</summary>
1900 <description>For the Pantheon and GNOME desktop shells, the player's window is simply minimized due to the lack of a minimize button; the window is hidden for all the rest of desktop shells, unless they are added to this key. In fact, any dock-based shell should be part of this key, except those that lack a sound menu or in which the dock space is often limited (e.g. Unity). See the description of close-while-playing for more information.</description>
1901 </key>
1902- <key type="i" name="last-playlist-playing">
1903- <default>-1</default>
1904- <summary>ID of last playlist playing</summary>
1905- <description>ID of last playlist playing</description>
1906+ <key type="s" name="last-playlist-playing">
1907+ <default>''</default>
1908+ <summary>'s' for smart playlist or 'p' for static playlist + ID of last playlist playing</summary>
1909+ <description>'s' for smart playlist or 'p' for static playlist + ID of last playlist playing</description>
1910 </key>
1911- <key type="i" name="last-media-playing">
1912+ <key type="x" name="last-media-playing">
1913 <default>0</default>
1914 <summary>ID of last media playing</summary>
1915 <description>ID of last media playing</description>
1916
1917=== modified file 'src/CMakeLists.txt'
1918--- src/CMakeLists.txt 2015-06-12 16:10:33 +0000
1919+++ src/CMakeLists.txt 2015-08-27 10:21:27 +0000
1920@@ -8,8 +8,12 @@
1921 Objects/MediaArtCache.vala
1922 Objects/CoverartCache.vala
1923 Objects/MediaKeyListener.vala
1924+ Objects/HistoryPlaylist.vala
1925 LocalBackend/LocalLibrary.vala
1926 LocalBackend/LocalMedia.vala
1927+ LocalBackend/LocalSmartPlaylist.vala
1928+ LocalBackend/LocalStaticPlaylist.vala
1929+ LocalBackend/DevicePreferences.vala
1930 Widgets/NavigationArrows.vala
1931 Widgets/TopDisplay.vala
1932 Widgets/InfoPanel.vala
1933@@ -30,9 +34,7 @@
1934 Widgets/FastView/FastGridModel.vala
1935 Widgets/FastView/FastList.vala
1936 Widgets/FastView/FastListModel.vala
1937- DataBase/DataBaseManager.vala
1938- DataBase/DataBaseUpdater.vala
1939- DataBase/Tables.vala
1940+ DataBase.vala
1941 GStreamer/GStreamerTagger.vala
1942 GStreamer/Streamer.vala
1943 GStreamer/CoverImport.vala
1944
1945=== removed directory 'src/DataBase'
1946=== renamed file 'src/DataBase/Tables.vala' => 'src/DataBase.vala'
1947--- src/DataBase/Tables.vala 2015-02-24 00:04:03 +0000
1948+++ src/DataBase.vala 2015-08-27 10:21:27 +0000
1949@@ -1,6 +1,6 @@
1950 // -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1951 /*-
1952- * Copyright (c) 2012 Noise Developers (http://launchpad.net/noise)
1953+ * Copyright (c) 2012-2015 Noise Developers (https://launchpad.net/noise)
1954 *
1955 * This library is free software; you can redistribute it and/or
1956 * modify it under the terms of the GNU Library General Public
1957@@ -26,38 +26,270 @@
1958 * statement from your version.
1959 */
1960
1961-namespace Noise.Database.Tables {
1962-
1963-public const string PLAYLISTS = """
1964-CREATE TABLE IF NOT EXISTS playlists (`name` TEXT, `media` TEXT,
1965-`sort_column_id` INT, `sort_direction` TEXT, `columns` TEXT)
1966-""";
1967-
1968-public const string SMART_PLAYLISTS = """
1969-CREATE TABLE IF NOT EXISTS smart_playlists (`name` TEXT, `and_or` INT, `queries` TEXT,
1970-`limit` INT, `limit_amount` INT)
1971-""";
1972-
1973-public const string COLUMNS = """
1974-CREATE TABLE IF NOT EXISTS columns (`is_smart` INT, `name` TEXT, `sort_column_id` INT, `sort_direction` TEXT,
1975-`columns` TEXT)
1976-""";
1977-
1978-public const string MEDIA = """
1979-CREATE TABLE IF NOT EXISTS media (`uri` TEXT, `file_size` INT, `title` TEXT,
1980-`artist` TEXT, `composer` TEXT, `album_artist` TEXT, `album` TEXT,
1981-`grouping` TEXT, `genre` TEXT,`comment` TEXT, `lyrics` TEXT, `has_embedded` INT,
1982-`year` INT, `track` INT, `track_count` INT, `album_number` INT,
1983-`album_count` INT, `bitrate` INT, `length` INT, `samplerate` INT, `rating` INT,
1984-`playcount` INT, `skipcount` INT, `dateadded` INT, `lastplayed` INT,
1985-`lastmodified` INT, `rowid` INTEGER PRIMARY KEY AUTOINCREMENT)
1986-""";
1987-
1988-public const string DEVICES = """
1989-CREATE TABLE IF NOT EXISTS devices (`unique_id` TEXT, `sync_when_mounted` INT,
1990-`sync_music` INT, `sync_podcasts` INT, `sync_audiobooks` INT, `sync_all_music` INT,
1991-`sync_all_podcasts` INT, `sync_all_audiobooks` INT, `music_playlist` STRING,
1992-`podcast_playlist` STRING, `audiobook_playlist` STRING, `last_sync_time` INT)
1993-""";
1994-
1995+namespace Noise.Database {
1996+ namespace Tables {
1997+ public const string PLAYLISTS = """CREATE TABLE IF NOT EXISTS playlists (name TEXT, media TEXT,
1998+ sort_column_id INT, sort_direction TEXT, columns TEXT, rowid INTEGER PRIMARY KEY AUTOINCREMENT)""";
1999+
2000+ public const string SMART_PLAYLISTS = """CREATE TABLE IF NOT EXISTS smart_playlists (name TEXT,
2001+ and_or INT, queries TEXT, limited INT, limit_amount INT, rowid INTEGER PRIMARY KEY AUTOINCREMENT)""";
2002+
2003+ public const string COLUMNS = """CREATE TABLE IF NOT EXISTS columns (unique_id TEXT, sort_column_id INT,
2004+ sort_direction INT, columns TEXT)""";
2005+
2006+ public const string MEDIA = """CREATE TABLE IF NOT EXISTS media (uri TEXT, file_size INT,
2007+ title TEXT, artist TEXT, composer TEXT, album_artist TEXT, album TEXT,
2008+ grouping TEXT, genre TEXT, comment TEXT, lyrics TEXT, has_embedded INT,
2009+ year INT, track INT, track_count INT, album_number INT,
2010+ album_count INT, bitrate INT, length INT, samplerate INT, rating INT,
2011+ playcount INT, skipcount INT, dateadded INT, lastplayed INT,
2012+ lastmodified INT, rowid INTEGER PRIMARY KEY AUTOINCREMENT)""";
2013+
2014+ public const string DEVICES = """CREATE TABLE IF NOT EXISTS devices (unique_id TEXT,
2015+ sync_when_mounted INT, sync_music INT, sync_all_music INT, music_playlist STRING,
2016+ last_sync_time INT)""";
2017+ }
2018+
2019+ /*
2020+ * NOTE:
2021+ * Update those constants when you change the order of columns.
2022+ */
2023+ namespace Playlists {
2024+ public static const string TABLE_NAME = "playlists";
2025+ public static const string NAME = "+0";
2026+ public static const string MEDIA = "+1";
2027+ public static const string SORT_COLUMN_ID = "+2";
2028+ public static const string SORT_DIRECTION = "+3";
2029+ public static const string COLUMNS = "+4";
2030+ public static const string ROWID = "+5";
2031+ }
2032+
2033+ namespace SmartPlaylists {
2034+ public static const string TABLE_NAME = "smart_playlists";
2035+ public static const string NAME = "+0";
2036+ public static const string AND_OR = "+1";
2037+ public static const string QUERIES = "+2";
2038+ public static const string LIMITED = "+3";
2039+ public static const string LIMIT_AMOUNT = "+4";
2040+ public static const string ROWID = "+5";
2041+ }
2042+
2043+ namespace Media {
2044+ public static const string TABLE_NAME = "media";
2045+ public static const string URI = "+0";
2046+ public static const string FILE_SIZE = "+1";
2047+ public static const string TITLE = "+2";
2048+ public static const string ARTIST = "+3";
2049+ public static const string COMPOSER = "+4";
2050+ public static const string ALBUM_ARTIST = "+5";
2051+ public static const string ALBUM = "+6";
2052+ public static const string GROUPING = "+7";
2053+ public static const string GENRE = "+8";
2054+ public static const string COMMENT = "+9";
2055+ public static const string LYRICS = "+10";
2056+ public static const string HAS_EMBEDDED = "+11";
2057+ public static const string YEAR = "+12";
2058+ public static const string TRACK = "+13";
2059+ public static const string TRACK_COUNT = "+14";
2060+ public static const string ALBUM_NUMBER = "+15";
2061+ public static const string ALBUM_COUNT = "+16";
2062+ public static const string BITRATE = "+17";
2063+ public static const string LENGTH = "+18";
2064+ public static const string SAMPLERATE = "+19";
2065+ public static const string RATING = "+20";
2066+ public static const string PLAYCOUNT = "+21";
2067+ public static const string SKIPCOUNT = "+22";
2068+ public static const string DATEADDED = "+23";
2069+ public static const string LASTPLAYED = "+24";
2070+ public static const string LASTMODIFIED = "+25";
2071+ public static const string ROWID = "+26";
2072+ }
2073+
2074+ namespace Devices {
2075+ public static const string TABLE_NAME = "devices";
2076+ public static const string UNIQUE_ID = "+0";
2077+ public static const string SYNC_WHEN_MOUNTED = "+1";
2078+ public static const string SYNC_MUSIC = "+2";
2079+ public static const string SYNC_ALL_MUSIC = "+3";
2080+ public static const string MUSIC_PLAYLIST = "+4";
2081+ public static const string LAST_SYNC_TIME = "+5";
2082+ }
2083+
2084+ namespace Columns {
2085+ public static const string TABLE_NAME = "columns";
2086+ public static const string UNIQUE_ID = "+0";
2087+ public static const string SORT_COLUMN_ID = "+1";
2088+ public static const string SORT_DIRECTION = "+2";
2089+ public static const string COLUMNS = "+3";
2090+ }
2091+
2092+ /*
2093+ * Helper functions.
2094+ */
2095+ public static Value make_string_value (string str) {
2096+ var val = Value (typeof(string));
2097+ val.set_string (str);
2098+ return val;
2099+ }
2100+
2101+ public static Value make_bool_value (bool bl) {
2102+ var val = Value (typeof(bool));
2103+ val.set_boolean (bl);
2104+ return val;
2105+ }
2106+
2107+ public static Value make_uint_value (uint u) {
2108+ var val = Value (typeof(uint));
2109+ val.set_uint (u);
2110+ return val;
2111+ }
2112+
2113+ public static Value make_int_value (int u) {
2114+ var val = Value (typeof(int));
2115+ val.set_int (u);
2116+ return val;
2117+ }
2118+
2119+ public static Value make_int64_value (int64 u) {
2120+ var val = Value (typeof(int64));
2121+ val.set_int64 (u);
2122+ return val;
2123+ }
2124+
2125+ public static Value make_uint64_value (uint64 u) {
2126+ var val = Value (typeof(uint64));
2127+ val.set_uint64 (u);
2128+ return val;
2129+ }
2130+
2131+ public static GLib.Value? query_field (int64 rowid, Gda.Connection connection, string table, string field) {
2132+ try {
2133+ var sql = new Gda.SqlBuilder (Gda.SqlStatementType.SELECT);
2134+ sql.select_add_target (table, null);
2135+ sql.add_field_value_id (sql.add_id (field), 0);
2136+ var id_field = sql.add_id ("rowid");
2137+ var id_param = sql.add_expr_value (null, Database.make_int64_value (rowid));
2138+ var id_cond = sql.add_cond (Gda.SqlOperatorType.EQ, id_field, id_param, 0);
2139+ sql.set_where (id_cond);
2140+ var data_model = connection.statement_execute_select (sql.get_statement (), null);
2141+ return data_model.get_value_at (data_model.get_column_index (field), 0);
2142+ } catch (Error e) {
2143+ critical ("Could not query field %s: %s", field, e.message);
2144+ return null;
2145+ }
2146+ }
2147+
2148+ public static void set_field (int64 rowid, Gda.Connection connection, string table, string field, GLib.Value value) {
2149+ try {
2150+ var rowid_value = GLib.Value (typeof (int64));
2151+ rowid_value.set_int64 (rowid);
2152+ var col_names = new GLib.SList<string> ();
2153+ col_names.append (field);
2154+ var values = new GLib.SList<GLib.Value?> ();
2155+ values.append (value);
2156+ connection.update_row_in_table_v (table, "rowid", rowid_value, col_names, values);
2157+ } catch (Error e) {
2158+ critical ("Could not set field %s: %s", field, e.message);
2159+ }
2160+ }
2161+
2162+ public static Gda.SqlBuilderId process_smart_query (Gda.SqlBuilder builder, SmartQuery sq) {
2163+ Value value = Value (sq.value.type ());
2164+ sq.value.copy (ref value);
2165+ string field;
2166+ switch (sq.field) {
2167+ case SmartQuery.FieldType.ALBUM:
2168+ field = "album";
2169+ break;
2170+ case SmartQuery.FieldType.ARTIST:
2171+ field = "artist";
2172+ break;
2173+ case SmartQuery.FieldType.BITRATE:
2174+ field = "bitrate";
2175+ break;
2176+ case SmartQuery.FieldType.COMMENT:
2177+ field = "comment";
2178+ break;
2179+ case SmartQuery.FieldType.COMPOSER:
2180+ field = "composer";
2181+ break;
2182+ case SmartQuery.FieldType.DATE_ADDED:
2183+ // We need the current timestamp because this field is relative.
2184+ value = Value (typeof (int));
2185+ value.set_int ((int)time_t ());
2186+ field = "dateadded";
2187+ break;
2188+ case SmartQuery.FieldType.GENRE:
2189+ field = "genre";
2190+ break;
2191+ case SmartQuery.FieldType.GROUPING:
2192+ field = "grouping";
2193+ break;
2194+ case SmartQuery.FieldType.LAST_PLAYED:
2195+ // We need the current timestamp because this field is relative.
2196+ value = Value (typeof (int));
2197+ value.set_int ((int)time_t ());
2198+ field = "lastplayed";
2199+ break;
2200+ case SmartQuery.FieldType.LENGTH:
2201+ field = "length";
2202+ break;
2203+ case SmartQuery.FieldType.PLAYCOUNT:
2204+ field = "playcount";
2205+ break;
2206+ case SmartQuery.FieldType.RATING:
2207+ field = "rating";
2208+ break;
2209+ case SmartQuery.FieldType.SKIPCOUNT:
2210+ field = "skipcount";
2211+ break;
2212+ case SmartQuery.FieldType.YEAR:
2213+ field = "year";
2214+ break;
2215+ case SmartQuery.FieldType.TITLE:
2216+ default:
2217+ field = "title";
2218+ break;
2219+ }
2220+
2221+ Gda.SqlOperatorType sql_operator_type;
2222+ switch (sq.comparator) {
2223+ case SmartQuery.ComparatorType.IS_NOT:
2224+ sql_operator_type = Gda.SqlOperatorType.NOT;
2225+ break;
2226+ case SmartQuery.ComparatorType.CONTAINS:
2227+ case SmartQuery.ComparatorType.NOT_CONTAINS:
2228+ value = make_string_value ("%" + value.get_string () + "%");
2229+ sql_operator_type = Gda.SqlOperatorType.LIKE;
2230+ break;
2231+ case SmartQuery.ComparatorType.IS_EXACTLY:
2232+ sql_operator_type = Gda.SqlOperatorType.EQ;
2233+ break;
2234+ case SmartQuery.ComparatorType.IS_AT_MOST:
2235+ sql_operator_type = Gda.SqlOperatorType.LEQ;
2236+ break;
2237+ case SmartQuery.ComparatorType.IS_AT_LEAST:
2238+ sql_operator_type = Gda.SqlOperatorType.GEQ;
2239+ break;
2240+ case SmartQuery.ComparatorType.IS_WITHIN:
2241+ sql_operator_type = Gda.SqlOperatorType.LEQ;
2242+ break;
2243+ case SmartQuery.ComparatorType.IS_BEFORE:
2244+ sql_operator_type = Gda.SqlOperatorType.GEQ;
2245+ break;
2246+ case SmartQuery.ComparatorType.IS:
2247+ default:
2248+ sql_operator_type = Gda.SqlOperatorType.LIKE;
2249+ break;
2250+ }
2251+
2252+ var id_field = builder.add_id (field);
2253+ var id_value = builder.add_expr_value (null, value);
2254+ if (sq.comparator == SmartQuery.ComparatorType.NOT_CONTAINS) {
2255+ var cond = builder.add_cond (sql_operator_type, id_field, id_value, 0);;
2256+ return builder.add_cond (Gda.SqlOperatorType.NOT, cond, 0, 0);
2257+ } else {
2258+ return builder.add_cond (sql_operator_type, id_field, id_value, 0);
2259+ }
2260+ }
2261 }
2262
2263=== removed file 'src/DataBase/DataBaseManager.vala'
2264--- src/DataBase/DataBaseManager.vala 2015-02-26 17:15:44 +0000
2265+++ src/DataBase/DataBaseManager.vala 1970-01-01 00:00:00 +0000
2266@@ -1,937 +0,0 @@
2267-/*
2268- * Copyright (c) 2012 Noise Developers
2269- *
2270- * This library is free software; you can redistribute it and/or
2271- * modify it under the terms of the GNU General Public License as
2272- * published by the Free Software Foundation; either version 2 of the
2273- * License, or (at your option) any later version.
2274- *
2275- * This is distributed in the hope that it will be useful,
2276- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2277- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2278- * Lesser General Public License for more details.
2279- *
2280- * You should have received a copy of the GNU Lesser General Public
2281- * License along with this program; see the file COPYING. If not,
2282- * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2283- * Boston, MA 02111-1307, USA.
2284- *
2285- * Authored by: Scott Ringwelski <sgringwe@mtu.edu>,
2286- * Victor Eduardo <victoreduardm@gmail.com>
2287- */
2288-
2289-using SQLHeavy;
2290-
2291-public class Noise.DataBaseManager : GLib.Object {
2292- public SQLHeavy.Database database;
2293- private Transaction transaction; // the current sql transaction
2294-
2295- private int index = 0;
2296- private int item_count = 0;
2297-
2298- private static DataBaseManager? dbm = null;
2299-
2300- public static DataBaseManager get_default () {
2301- if (dbm == null)
2302- dbm = new DataBaseManager ();
2303- return dbm;
2304- }
2305-
2306- /** Creates a new DatabaseManager **/
2307- private DataBaseManager () {
2308- init_database ();
2309- }
2310-
2311- /** Creates/Reads the database file and folder **/
2312- private void init_database () {
2313- assert (database == null);
2314-
2315- var database_dir = FileUtils.get_data_directory ();
2316-
2317- try {
2318- database_dir.make_directory_with_parents (null);
2319- }
2320- catch (GLib.Error err) {
2321- if (!(err is IOError.EXISTS))
2322- error ("Could not create data directory: %s", err.message);
2323- }
2324-
2325- string database_path = Path.build_filename (database_dir.get_path (), "database_0_3_0.db");
2326- var database_file = File.new_for_path (database_path);
2327-
2328- bool new_db = !database_file.query_exists ();
2329-
2330- try {
2331- const SQLHeavy.FileMode flags = SQLHeavy.FileMode.READ
2332- | SQLHeavy.FileMode.WRITE
2333- | SQLHeavy.FileMode.CREATE;
2334- database = new SQLHeavy.Database (database_file.get_path (), flags);
2335- }
2336- catch (SQLHeavy.Error err) {
2337- error ("Could not read/create database file: %s", err.message);
2338- }
2339-
2340- // Disable synchronized commits for performance reasons
2341- database.synchronous = SQLHeavy.SynchronousMode.OFF;
2342-
2343- load_table (Database.Tables.PLAYLISTS);
2344- load_table (Database.Tables.SMART_PLAYLISTS);
2345- load_table (Database.Tables.COLUMNS);
2346- load_table (Database.Tables.MEDIA);
2347- load_table (Database.Tables.DEVICES);
2348-
2349- if (new_db)
2350- add_default_smart_playlists ();
2351- }
2352-
2353- private void load_table (string table) {
2354- try {
2355- database.execute (table);
2356- }
2357- catch (SQLHeavy.Error err) {
2358- warning ("Error while executing %s: %s", table, err.message);
2359- }
2360- }
2361-
2362- public void resetProgress (int items) {
2363- index = 0;
2364- item_count = items;
2365- }
2366-
2367- /**
2368- * Loads media from db
2369- */
2370- public Gee.TreeSet<LocalMedia> load_media () {
2371- assert (database != null);
2372- var rv = new Gee.TreeSet<LocalMedia>();
2373-
2374- try {
2375- Query query = new Query (database, "SELECT `rowid` FROM `media`");
2376- for (var results = query.execute (); !results.finished; results.next()) {
2377- var m = new LocalMedia (results.fetch_int ());
2378- rv.add (m);
2379- }
2380- }
2381- catch (SQLHeavy.Error err) {
2382- warning ("Could not load media from db: %s\n", err.message);
2383- }
2384-
2385- return rv;
2386- }
2387-
2388- public void clear_media () {
2389- assert (database != null);
2390- try {
2391- database.execute ("DELETE FROM `media`");
2392- }
2393- catch(SQLHeavy.Error err) {
2394- warning ("Could not clear media: %s \n", err.message);
2395- }
2396- }
2397-
2398- public Gee.TreeSet<LocalMedia> add_media (Gee.Collection<Media> media) {
2399- assert (database != null);
2400- var tree_set = new Gee.TreeSet<LocalMedia> ();
2401- try {
2402- Query query = new Query (database, """INSERT INTO `media` (`uri`, `file_size`, `title`, `artist`, `composer`, `album_artist`,
2403-`album`, `grouping`, `genre`, `comment`, `lyrics`, `has_embedded`, `year`, `track`, `track_count`, `album_number`, `album_count`,
2404-`bitrate`, `length`, `samplerate`, `rating`, `playcount`, `skipcount`, `dateadded`, `lastplayed`, `lastmodified`)
2405-VALUES (:uri, :file_size, :title, :artist, :composer, :album_artist, :album, :grouping,
2406-:genre, :comment, :lyrics, :has_embedded, :year, :track, :track_count, :album_number, :album_count, :bitrate, :length, :samplerate,
2407-:rating, :playcount, :skipcount, :dateadded, :lastplayed, :lastmodified);""");
2408-
2409- foreach (var s in media) {
2410- if (!s.isTemporary) {
2411- query.set_string(":uri", s.uri);
2412- query.set_int(":file_size", (int)s.file_size);
2413- query.set_string(":title", s.title);
2414- query.set_string(":artist", s.artist);
2415- query.set_string(":composer", s.composer);
2416- query.set_string(":album_artist", s.album_artist);
2417- query.set_string(":album", s.album);
2418- query.set_string(":grouping", s.grouping);
2419- query.set_string(":genre", s.genre);
2420- query.set_string(":comment", s.comment);
2421- query.set_string(":lyrics", s.lyrics);
2422- query.set_int(":has_embedded", s.has_embedded ? 1 : 0);
2423- query.set_int(":year", (int)s.year);
2424- query.set_int(":track", (int)s.track);
2425- query.set_int(":track_count", (int)s.track_count);
2426- query.set_int(":album_number", (int)s.album_number);
2427- query.set_int(":album_count", (int)s.album_count);
2428- query.set_int(":bitrate", (int)s.bitrate);
2429- query.set_int(":length", (int)s.length);
2430- query.set_int(":samplerate", (int)s.samplerate);
2431- query.set_int(":rating", (int)s.rating);
2432- query.set_int(":playcount", (int)s.play_count);
2433- query.set_int(":skipcount", (int)s.skip_count);
2434- query.set_int(":dateadded", (int)s.date_added);
2435- query.set_int(":lastplayed", (int)s.last_played);
2436- query.set_int(":lastmodified", (int)s.last_modified);
2437- query.execute ();
2438- var local_media = new LocalMedia ((int)database.last_insert_id);
2439- tree_set.add (local_media);
2440- }
2441- }
2442- }
2443- catch (SQLHeavy.Error err) {
2444- warning ("Could not save media: %s \n", err.message);
2445- }
2446- return tree_set;
2447- }
2448-
2449- public void remove_media (Gee.Collection<Media> media) {
2450- assert (database != null);
2451- try {
2452- transaction = database.begin_transaction();
2453- Query query = transaction.prepare ("DELETE FROM `media` WHERE rowid=:rowid");
2454-
2455- foreach (var m in media) {
2456- query.set_int (":rowid", m.rowid);
2457- query.execute ();
2458- }
2459-
2460- transaction.commit ();
2461- }
2462- catch (SQLHeavy.Error err) {
2463- warning ("Could not remove media from db: %s\n", err.message);
2464- }
2465- }
2466-
2467- /** COLUMNS STATE **
2468- * load_columns_state() loads the state of each columns from db
2469- *
2470- */
2471- public Gee.HashMap<Playlist, TreeViewSetup> load_columns_state () {
2472- debug ("load columns");
2473- assert (database != null);
2474- var rv = new Gee.HashMap<Playlist, TreeViewSetup>();
2475-
2476- try {
2477- string script = "SELECT * FROM `columns`";
2478- Query query = new Query(database, script);
2479-
2480- for (var results = query.execute(); !results.finished; results.next() ) {
2481- if (results.fetch_int(0) == 0) {
2482- StaticPlaylist p = libraries_manager.local_library.playlist_from_name (results.fetch_string(1));
2483- var tvs = new TreeViewSetup (results.fetch_int(2), Gtk.SortType.ASCENDING, ViewWrapper.Hint.PLAYLIST);
2484- tvs.set_sort_direction_from_string(results.fetch_string(3));
2485- tvs.import_columns(results.fetch_string(4));
2486- rv.set (p, tvs);
2487- } else {
2488- SmartPlaylist p = libraries_manager.local_library.smart_playlist_from_name (results.fetch_string(1));
2489- var tvs = new TreeViewSetup (results.fetch_int(2), Gtk.SortType.ASCENDING, ViewWrapper.Hint.SMART_PLAYLIST);
2490- tvs.set_sort_direction_from_string(results.fetch_string(3));
2491- tvs.import_columns(results.fetch_string(4));
2492- rv.set (p, tvs);
2493- }
2494- }
2495- }
2496- catch (SQLHeavy.Error err) {
2497- warning ("Could not load columns from db: %s\n", err.message);
2498- }
2499-
2500- return rv;
2501- }
2502-
2503- public void save_columns_state (Gee.Collection<StaticPlaylist>? playlists = null, Gee.Collection<SmartPlaylist>? smart_playlists = null) {
2504- debug ("save columns");
2505- assert (database != null);
2506- try {
2507- database.execute("DELETE FROM `columns`");
2508- transaction = database.begin_transaction();
2509- Query query = transaction.prepare ("""INSERT INTO `columns` (`is_smart`, `name`, `sort_column_id`, `sort_direction`, `columns`)
2510- VALUES (:is_smart, :name, :sort_column_id, :sort_direction, :columns);""");
2511-
2512- if (playlists != null) {
2513- foreach(StaticPlaylist p in playlists) {
2514- if (p.read_only == false) {
2515- var tvs = App.main_window.get_treeviewsetup_from_playlist (p);
2516-
2517- query.set_int (":is_smart", 0);
2518- query.set_string (":name", p.name);
2519- query.set_int (":sort_column_id", tvs.sort_column_id);
2520- query.set_string (":sort_direction", tvs.sort_direction_to_string());
2521- query.set_string (":columns", tvs.columns_to_string());
2522-
2523- query.execute();
2524- }
2525- }
2526- }
2527-
2528- if (smart_playlists != null) {
2529- foreach(SmartPlaylist p in smart_playlists) {
2530- var tvs = App.main_window.get_treeviewsetup_from_playlist (p);
2531-
2532- query.set_int (":is_smart", 1);
2533- query.set_string (":name", p.name);
2534- query.set_int (":sort_column_id", tvs.sort_column_id);
2535- query.set_string (":sort_direction", tvs.sort_direction_to_string());
2536- query.set_string (":columns", tvs.columns_to_string());
2537-
2538- query.execute();
2539- }
2540- }
2541-
2542- transaction.commit();
2543- }
2544- catch(SQLHeavy.Error err) {
2545- warning ("Could not save playlists: %s \n", err.message);
2546- }
2547- }
2548-
2549- public void add_columns_state (StaticPlaylist? p = null, SmartPlaylist? sp = null) {
2550- debug ("add columns");
2551- assert (database != null);
2552-
2553- string name = "";
2554- int is_smart = 0;
2555- TreeViewSetup tvs;
2556- if (sp == null) {
2557- if (p == null)
2558- return;
2559- if (p.read_only == true)
2560- return;
2561- name = p.name;
2562- tvs = App.main_window.get_treeviewsetup_from_playlist (p);
2563- } else {
2564- if (sp == null)
2565- return;
2566- is_smart = 1;
2567- name = sp.name;
2568- tvs = App.main_window.get_treeviewsetup_from_playlist (sp);
2569- }
2570-
2571- try {
2572- transaction = database.begin_transaction();
2573- Query query = transaction.prepare ("""INSERT INTO `columns` (`is_smart`, `name`, `sort_column_id`, `sort_direction`, `columns`)
2574- VALUES (:is_smart, :name, :sort_column_id, :sort_direction, :columns);""");
2575-
2576- query.set_int (":is_smart", is_smart);
2577- query.set_string (":name", name);
2578- query.set_int (":sort_column_id", tvs.sort_column_id);
2579- query.set_string (":sort_direction", tvs.sort_direction_to_string());
2580- query.set_string (":columns", tvs.columns_to_string());
2581- query.execute();
2582-
2583- transaction.commit();
2584- }
2585- catch(SQLHeavy.Error err) {
2586- warning ("Could not add columns: %s \n", err.message);
2587- }
2588- }
2589-
2590- public void remove_columns_state (StaticPlaylist? p = null, SmartPlaylist? sp = null) {
2591- debug ("remove columns");
2592- assert (database != null);
2593-
2594- string name = "";
2595- if (sp == null) {
2596- if (p == null)
2597- return;
2598- if (p.read_only == true)
2599- return;
2600- name = p.name;
2601- } else {
2602- if (sp == null)
2603- return;
2604- name = sp.name;
2605- }
2606- try {
2607- transaction = database.begin_transaction();
2608- Query query = transaction.prepare("""DELETE FROM `columns` WHERE name=:name""");
2609-
2610- query.set_string(":name", name);
2611- query.execute();
2612-
2613- transaction.commit();
2614- }
2615- catch (SQLHeavy.Error err) {
2616- warning ("Could not remove column from db: %s\n", err.message);
2617- }
2618- }
2619-
2620- public void add_default_columns () {
2621- assert (database != null);
2622- try {
2623-
2624- TreeViewSetup tvs = new TreeViewSetup (ListColumn.ARTIST, Gtk.SortType.ASCENDING, ViewWrapper.Hint.SMART_PLAYLIST);
2625-
2626- transaction = database.begin_transaction();
2627- Query query = transaction.prepare ("""INSERT INTO `columns` (`is_smart`, `name`, `sort_column_id`, `sort_direction`, `columns`)
2628- VALUES (:is_smart, :name, :sort_column_id, :sort_direction, :columns);""");
2629-
2630- query.set_int (":is_smart", 1);
2631- query.set_string (":name", _("Favorite Songs"));
2632- query.set_int (":sort_column_id", ListColumn.RATING);
2633- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2634- query.set_string (":columns", tvs.columns_to_string ());
2635- query.execute ();
2636-
2637- query.set_int (":is_smart", 1);
2638- query.set_string (":name", _("Recently Added"));
2639- query.set_int (":sort_column_id", ListColumn.ARTIST);
2640- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2641- query.set_string (":columns", tvs.columns_to_string ());
2642- query.execute ();
2643-
2644- /*
2645- query.set_int (":is_smart", 1);
2646- query.set_string (":name", _("Recently Played"));
2647- query.set_int (":sort_column_id", ListColumn.LAST_PLAYED);
2648- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2649- query.set_string (":columns", tvs.columns_to_string ());
2650- query.execute ();
2651- */
2652-
2653- query.set_int (":is_smart", 1);
2654- query.set_string (":name", _("Recent Favorites"));
2655- query.set_int (":sort_column_id", ListColumn.RATING);
2656- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2657- query.set_string (":columns", tvs.columns_to_string ());
2658- query.execute ();
2659-
2660- query.set_int (":is_smart", 1);
2661- query.set_string (":name", _("Never Played"));
2662- query.set_int (":sort_column_id", ListColumn.ARTIST);
2663- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2664- query.set_string (":columns", tvs.columns_to_string ());
2665- query.execute ();
2666-
2667- query.set_int (":is_smart", 1);
2668- query.set_string (":name", _("Over Played"));
2669- query.set_int (":sort_column_id", ListColumn.PLAY_COUNT);
2670- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2671- query.set_string (":columns", tvs.columns_to_string ());
2672- query.execute ();
2673-
2674- query.set_int (":is_smart", 1);
2675- query.set_string (":name", _("Not Recently Played"));
2676- query.set_int (":sort_column_id", ListColumn.NUMBER);
2677- query.set_string (":sort_direction", tvs.sort_direction_to_string ());
2678- query.set_string (":columns", tvs.columns_to_string ());
2679- query.execute ();
2680-
2681- transaction.commit();
2682- }
2683- catch (SQLHeavy.Error err) {
2684- warning ("Could not initialize columns: %s\n", err.message);
2685- }
2686- }
2687-
2688- /** PLAYLISTS **
2689- * load_playlists() loads playlists from db
2690- *
2691- * playlist_from_id loads playlist of given rowid
2692- *
2693- * playlist_from_name() loads playlsit given a name
2694- */
2695- public Gee.ArrayList<StaticPlaylist> load_playlists () {
2696- var rv = new Gee.ArrayList<StaticPlaylist>();
2697- assert (database != null);
2698-
2699- try {
2700- string script = "SELECT * FROM `playlists`";
2701- Query query = new Query(database, script);
2702-
2703- for (var results = query.execute(); !results.finished; results.next() ) {
2704- var p = new StaticPlaylist.with_info(0, results.fetch_string(0));
2705-
2706- string media = results.fetch_string(1);
2707-
2708- string[] media_strings = media.split("<sep>", 0);
2709- int index;
2710- var uris = new Gee.LinkedList<string> ();
2711- for (index = 0; index < media_strings.length - 1; ++index) {
2712- uris.add (media_strings[index]);
2713- }
2714- p.add_medias (libraries_manager.local_library.medias_from_uris (uris));
2715-
2716- if (!rv.contains (p))
2717- rv.add(p);
2718- }
2719- }
2720- catch (SQLHeavy.Error err) {
2721- warning ("Could not load playlists from db: %s\n", err.message);
2722- }
2723-
2724- return rv;
2725- }
2726-
2727- public void save_playlists (Gee.Collection<StaticPlaylist> playlists) {
2728- assert (database != null);
2729- try {
2730- database.execute("DELETE FROM `playlists`");
2731- transaction = database.begin_transaction();
2732- Query query = transaction.prepare ("INSERT INTO `playlists` (`name`, `media`) VALUES (:name, :media);");
2733-
2734- foreach (var p in playlists) {
2735- if (p.read_only == false || p.name == C_("Name of the playlist", "Queue") || p.name == _("History")) {
2736- string rv = "";
2737-
2738- foreach (var m in p.medias) {
2739- if (m != null)
2740- rv += m.uri + "<sep>";
2741- }
2742- query.set_string(":name", p.name);
2743- query.set_string(":media", rv);
2744-
2745- query.execute();
2746- }
2747- }
2748-
2749- transaction.commit();
2750- }
2751- catch(SQLHeavy.Error err) {
2752- warning ("Could not save playlists: %s \n", err.message);
2753- }
2754- }
2755-
2756- public void save_playlist (StaticPlaylist p, string? old_name = null) {
2757- assert (database != null);
2758- try {
2759- if (p.read_only == true)
2760- return;
2761-
2762- if (old_name == null) {
2763- remove_playlist (p);
2764- } else {
2765- var pl = new StaticPlaylist.with_info (0, old_name);
2766- remove_playlist (pl);
2767- }
2768- transaction = database.begin_transaction();
2769- Query query = transaction.prepare ("INSERT INTO `playlists` (`name`, `media`) VALUES (:name, :media);");
2770-
2771- string rv = "";
2772-
2773- foreach (var m in p.medias) {
2774- if (m != null)
2775- rv += m.uri + "<sep>";
2776- }
2777- query.set_string(":name", p.name);
2778- query.set_string(":media", rv);
2779-
2780- query.execute();
2781-
2782- transaction.commit();
2783- }
2784- catch(SQLHeavy.Error err) {
2785- warning ("Could not save playlists: %s \n", err.message);
2786- }
2787- }
2788-
2789- public void add_playlist (StaticPlaylist p) {
2790- assert (database != null);
2791- if (p.read_only == true)
2792- return;
2793- string rv = "";
2794-
2795- foreach (var m in p.medias) {
2796- if (m != null)
2797- rv += m.uri + "<sep>";
2798- }
2799-
2800- try {
2801- transaction = database.begin_transaction();
2802- Query query = transaction.prepare ("""INSERT INTO `playlists` (`name`, `media`)
2803- VALUES (:name, :media);""");
2804-
2805- query.set_string(":name", p.name);
2806- query.set_string(":media", rv);
2807-
2808- query.execute();
2809-
2810- transaction.commit();
2811-
2812- debug ("playlist %s stored into database", p.name);
2813- }
2814- catch(SQLHeavy.Error err) {
2815- warning ("Could not add playlists: %s \n", err.message);
2816- }
2817- }
2818-
2819- /*public void update_playlists(LinkedList<StaticPlaylist> playlists) {
2820- try {
2821- transaction = database.begin_transaction();
2822- Query query = transaction.prepare("UPDATE `playlists` SET name=:name, media=:media, sort_column_id=:sort_column_id, sort_direction=:sort_direction, columns=:columns WHERE name=:name");
2823-
2824- foreach (var p in playlists) {
2825- query.set_string(":name", p.name);
2826- query.set_string(":media", p.media_to_string(App.library_manager));
2827- query.set_int(":sort_column_id", p.tvs.sort_column_id);
2828- query.set_string(":sort_direction", p.tvs.sort_direction_to_string());
2829- query.set_string(":columns", p.tvs.columns_to_string());
2830-
2831- query.execute();
2832- }
2833-
2834- transaction.commit();
2835- }
2836- catch(SQLHeavy.Error err) {
2837- warning ("Could not update playlist: %s \n", err.message);
2838- }
2839- }*/
2840-
2841- public void remove_playlist (StaticPlaylist p) {
2842- assert (database != null);
2843- if (p.read_only == true)
2844- return;
2845- try {
2846- transaction = database.begin_transaction();
2847- Query query = transaction.prepare("""DELETE FROM `playlists` WHERE name=:name""");
2848-
2849- query.set_string(":name", p.name);
2850- query.execute();
2851-
2852- transaction.commit();
2853- }
2854- catch (SQLHeavy.Error err) {
2855- warning ("Could not remove playlist from db: %s\n", err.message);
2856- }
2857- }
2858-
2859- /** SMART PLAYLISTS **/
2860-
2861- private static const string QUERY_SEPARATOR = "<query_sep>";
2862- private static const string VALUE_SEPARATOR = "<val_sep>";
2863-
2864- /** temp_playlist should be in format of #,#,#,#,#, **/
2865- public static Gee.LinkedList<SmartQuery> queries_from_string (string q) {
2866- string[] queries_in_string = q.split(QUERY_SEPARATOR, 0);
2867- int index;
2868-
2869- var queries = new Gee.LinkedList<SmartQuery> ();
2870- for(index = 0; index < queries_in_string.length - 1; index++) {
2871- string[] pieces_of_query = queries_in_string[index].split(VALUE_SEPARATOR, 3);
2872- pieces_of_query.resize (3);
2873-
2874- SmartQuery sq = new SmartQuery();
2875- sq.field = (SmartQuery.FieldType)int.parse(pieces_of_query[0]);
2876- sq.comparator = (SmartQuery.ComparatorType)int.parse(pieces_of_query[1]);
2877- sq.value = pieces_of_query[2];
2878-
2879- queries.add (sq);
2880- }
2881-
2882- return queries;
2883- }
2884-
2885- // FIXME: This is an implementation detail and should not be present in the core.
2886- public static string queries_to_string (Gee.Collection<SmartQuery> queries) {
2887- string rv = "";
2888- foreach (SmartQuery q in queries) {
2889- rv += ((int)q.field).to_string () + VALUE_SEPARATOR + ((int)q.comparator).to_string() + VALUE_SEPARATOR + q.value + QUERY_SEPARATOR;
2890- }
2891-
2892- return rv;
2893- }
2894-
2895- public void add_default_smart_playlists () {
2896- assert (database != null);
2897- try {
2898- transaction = database.begin_transaction();
2899- Query query = transaction.prepare ("""INSERT INTO `smart_playlists` (`name`, `and_or`, `queries`, `limit`, `limit_amount`) VALUES (:name, :and_or, :queries, :limit, :limit_amount);""");
2900-
2901- query.set_string(":name", _("Favorite Songs"));
2902- query.set_int(":and_or", 1);
2903- query.set_string(":queries", "11<val_sep>2<val_sep>4<query_sep>13<val_sep>0<val_sep>0<query_sep>12<val_sep>6<val_sep>3<query_sep>");
2904- query.set_int(":limit", 1);
2905- query.set_int(":limit_amount", 50);
2906- query.execute();
2907-
2908- query.set_string(":name", _("Recently Added"));
2909- query.set_int(":and_or", 1);
2910- query.set_string(":queries", "5<val_sep>7<val_sep>7<query_sep>");
2911- query.set_int(":limit", 1);
2912- query.set_int(":limit_amount", 50);
2913- query.execute();
2914-
2915- /*
2916- query.set_string(":name", _("Recently Played"));
2917- query.set_int(":and_or", 1);
2918- query.set_string(":queries", "9<val_sep>7<val_sep>7<query_sep>");
2919- query.set_int(":limit", 0);
2920- query.set_int(":limit_amount", 50);
2921- query.execute();
2922- */
2923-
2924- query.set_string(":name", _("Recent Favorites"));
2925- query.set_int(":and_or", 1);
2926- query.set_string(":queries", "11<val_sep>2<val_sep>4<query_sep>13<val_sep>0<val_sep>0<query_sep>9<val_sep>7<val_sep>7<query_sep>");
2927- query.set_int(":limit", 1);
2928- query.set_int(":limit_amount", 50);
2929- query.execute();
2930-
2931- query.set_string(":name", _("Never Played"));
2932- query.set_int(":and_or", 0);
2933- query.set_string(":queries", "11<val_sep>0<val_sep>0<query_sep>");
2934- query.set_int(":limit", 1);
2935- query.set_int(":limit_amount", 50);
2936- query.execute();
2937-
2938- query.set_string(":name", _("Over Played"));
2939- query.set_int(":and_or", 1);
2940- query.set_string(":queries", "11<val_sep>4<val_sep>10<query_sep>");
2941- query.set_int(":limit", 1);
2942- query.set_int(":limit_amount", 50);
2943- query.execute();
2944-
2945- query.set_string(":name", _("Not Recently Played"));
2946- query.set_int(":and_or", 1);
2947- query.set_string(":queries", "9<val_sep>8<val_sep>7<query_sep>");
2948- query.set_int(":limit", 1);
2949- query.set_int(":limit_amount", 50);
2950- query.execute();
2951-
2952- transaction.commit();
2953- }
2954- catch (SQLHeavy.Error err) {
2955- warning ("Could not initialize smart playlists: %s\n", err.message);
2956- }
2957- }
2958-
2959- public Gee.ArrayList<SmartPlaylist> load_smart_playlists() {
2960- var rv = new Gee.ArrayList<SmartPlaylist>();
2961- assert (database != null);
2962-
2963- try {
2964- string script = "SELECT * FROM `smart_playlists`";
2965- Query query = new Query(database, script);
2966-
2967- for (var results = query.execute(); !results.finished; results.next() ) {
2968- SmartPlaylist p = new SmartPlaylist (libraries_manager.local_library);
2969-
2970- p.name = results.fetch_string(0);
2971- p.conditional = (SmartPlaylist.ConditionalType)results.fetch_int(1);
2972- p.add_queries (queries_from_string(results.fetch_string (2)));
2973- p.limit = ( results.fetch_string(3) == "1") ? true : false;
2974- p.limit_amount = results.fetch_int(4);
2975-
2976- rv.add(p);
2977- }
2978- }
2979- catch (SQLHeavy.Error err) {
2980- warning ("Could not load smart playlists from db: %s\n", err.message);
2981- }
2982-
2983- return rv;
2984- }
2985-
2986- public void save_smart_playlists(Gee.Collection<SmartPlaylist> smarts) {
2987- assert (database != null);
2988- try {
2989- database.execute("DELETE FROM `smart_playlists`");
2990- transaction = database.begin_transaction();
2991- Query query = transaction.prepare ("INSERT INTO `smart_playlists` (`name`, `and_or`, `queries`, `limit`, `limit_amount`) VALUES (:name, :and_or, :queries, :limit, :limit_amount);");
2992-
2993- foreach(SmartPlaylist s in smarts) {
2994- query.set_string(":name", s.name);
2995- query.set_int(":and_or", (int)s.conditional);
2996- query.set_string(":queries", queries_to_string (s.get_queries ()));
2997- query.set_int(":limit", ( s.limit ) ? 1 : 0);
2998- query.set_int(":limit_amount", s.limit_amount);
2999-
3000- query.execute();
3001- }
3002-
3003- transaction.commit();
3004- } catch (SQLHeavy.Error err) {
3005- warning ("Could not save smart playlists: %s \n", err.message);
3006- }
3007- }
3008-
3009- public void save_smart_playlist (SmartPlaylist p, string? old_name = null) {
3010- assert (database != null);
3011- if (old_name == null) {
3012- remove_smart_playlist (p);
3013- } else {
3014- var sp = new SmartPlaylist (libraries_manager.local_library);
3015- sp.name = old_name;
3016- remove_smart_playlist (sp);
3017- }
3018-
3019- try {
3020- transaction = database.begin_transaction();
3021- Query query = transaction.prepare("""INSERT INTO `smart_playlists` (`name`, `and_or`, `queries`, `limit`, `limit_amount`) VALUES (:name, :and_or, :queries, :limit, :limit_amount);""");
3022-
3023- query.set_string(":name", p.name);
3024- query.set_int(":and_or", (int)p.conditional);
3025- query.set_string(":queries", queries_to_string (p.get_queries ()));
3026- query.set_int(":limit", ( p.limit ) ? 1 : 0);
3027- query.set_int(":limit_amount", p.limit_amount);
3028-
3029- query.execute();
3030- transaction.commit();
3031- } catch(SQLHeavy.Error err) {
3032- warning ("Could not update smart playlist: %s \n", err.message);
3033- }
3034- }
3035-
3036- public void remove_smart_playlist (SmartPlaylist p) {
3037- assert (database != null);
3038- try {
3039- transaction = database.begin_transaction();
3040- Query query = transaction.prepare("""DELETE FROM `smart_playlists` WHERE name=:name""");
3041-
3042- query.set_string(":name", p.name);
3043- query.execute();
3044-
3045- transaction.commit();
3046- } catch (SQLHeavy.Error err) {
3047- warning ("Could not remove smart playlist from db: %s\n", err.message);
3048- }
3049- }
3050-
3051- public Gee.Collection<DevicePreferences> load_devices() {
3052- assert (database != null);
3053- var rv = new Gee.ArrayList<DevicePreferences>();
3054-
3055- try {
3056- string script = """SELECT rowid,* FROM `devices`""";
3057- Query query = new Query(database, script);
3058-
3059- for (var results = query.execute(); !results.finished; results.next() ) {
3060- DevicePreferences dp = new DevicePreferences(results.fetch_string(1));
3061-
3062- dp.sync_when_mounted = (results.fetch_int(2) == 1);
3063- dp.sync_music = (results.fetch_int(3) == 1);
3064- dp.sync_podcasts = (results.fetch_int(4) == 1);
3065- dp.sync_audiobooks = (results.fetch_int(5) == 1);
3066- dp.sync_all_music = (results.fetch_int(6) == 1);
3067- dp.sync_all_podcasts = (results.fetch_int(7) == 1);
3068- dp.sync_all_audiobooks = (results.fetch_int(8) == 1);
3069- if (results.fetch_string(9) != null) {
3070- dp.music_playlist = libraries_manager.local_library.playlist_from_name (results.fetch_string(9));
3071- if (dp.music_playlist == null)
3072- dp.music_playlist = libraries_manager.local_library.smart_playlist_from_name (results.fetch_string(9));
3073- }
3074- if (results.fetch_string(10) != null) {
3075- dp.podcast_playlist = libraries_manager.local_library.playlist_from_name (results.fetch_string(10));
3076- if (dp.podcast_playlist == null)
3077- dp.podcast_playlist = libraries_manager.local_library.smart_playlist_from_name (results.fetch_string(10));
3078- }
3079- if (results.fetch_string(11) != null) {
3080- dp.audiobook_playlist = libraries_manager.local_library.playlist_from_name (results.fetch_string(11));
3081- if (dp.audiobook_playlist == null)
3082- dp.audiobook_playlist = libraries_manager.local_library.smart_playlist_from_name (results.fetch_string(11));
3083- }
3084- dp.last_sync_time = results.fetch_int(12);
3085-
3086- rv.add (dp);
3087- }
3088- } catch (SQLHeavy.Error err) {
3089- warning ("Could not load devices from db: %s\n", err.message);
3090- }
3091-
3092- return rv;
3093- }
3094-
3095- public void save_devices(Gee.Collection<DevicePreferences> devices) {
3096- assert (database != null);
3097- try {
3098- database.execute("DELETE FROM `devices`");
3099- transaction = database.begin_transaction();
3100- Query query = transaction.prepare("""INSERT INTO `devices` (`unique_id`, `sync_when_mounted`, `sync_music`,
3101- `sync_podcasts`, `sync_audiobooks`, `sync_all_music`, `sync_all_podcasts`, `sync_all_audiobooks`, `music_playlist`,
3102- `podcast_playlist`, `audiobook_playlist`, `last_sync_time`) VALUES (:unique_id, :sync_when_mounted, :sync_music, :sync_podcasts, :sync_audiobooks,
3103- :sync_all_music, :sync_all_podcasts, :sync_all_audiobooks, :music_playlist, :podcast_playlist, :audiobook_playlist, :last_sync_time);""");
3104-
3105- foreach(DevicePreferences dp in devices) {
3106- query.set_string(":unique_id", dp.id);
3107- query.set_int(":sync_when_mounted", dp.sync_when_mounted ? 1 : 0);
3108-
3109- query.set_int(":sync_music", dp.sync_music ? 1 : 0);
3110- query.set_int(":sync_podcasts", dp.sync_podcasts ? 1 : 0);
3111- query.set_int(":sync_audiobooks", dp.sync_audiobooks ? 1 : 0);
3112-
3113- query.set_int(":sync_all_music", dp.sync_all_music ? 1 : 0);
3114- query.set_int(":sync_all_podcasts", dp.sync_all_podcasts ? 1 : 0);
3115- query.set_int(":sync_all_audiobooks", dp.sync_all_audiobooks ? 1 : 0);
3116-
3117- string music_playlist = "";
3118- string podcast_playlist = "";
3119- string audiobook_playlist = "";
3120-
3121- if (dp.music_playlist != null)
3122- music_playlist = dp.music_playlist.name;
3123- if (dp.podcast_playlist != null)
3124- podcast_playlist = dp.podcast_playlist.name;
3125- if (dp.audiobook_playlist != null)
3126- audiobook_playlist = dp.audiobook_playlist.name;
3127-
3128- query.set_string(":music_playlist", music_playlist);
3129- query.set_string(":podcast_playlist", podcast_playlist);
3130- query.set_string(":audiobook_playlist", audiobook_playlist);
3131- query.set_int(":last_sync_time", dp.last_sync_time);
3132-
3133- query.execute();
3134- }
3135-
3136- transaction.commit();
3137- } catch (SQLHeavy.Error err) {
3138- warning ("Could not save devices: %s\n", err.message);
3139- }
3140- }
3141-
3142- public void save_device (DevicePreferences dp) {
3143- assert (database != null);
3144- try {
3145- remove_device (dp);
3146- transaction = database.begin_transaction();
3147- Query query = transaction.prepare("""INSERT INTO `devices` (`unique_id`, `sync_when_mounted`, `sync_music`,
3148- `sync_podcasts`, `sync_audiobooks`, `sync_all_music`, `sync_all_podcasts`, `sync_all_audiobooks`, `music_playlist`,
3149- `podcast_playlist`, `audiobook_playlist`, `last_sync_time`) VALUES (:unique_id, :sync_when_mounted, :sync_music, :sync_podcasts, :sync_audiobooks,
3150- :sync_all_music, :sync_all_podcasts, :sync_all_audiobooks, :music_playlist, :podcast_playlist, :audiobook_playlist, :last_sync_time);""");
3151-
3152- query.set_string(":unique_id", dp.id);
3153- query.set_int(":sync_when_mounted", dp.sync_when_mounted ? 1 : 0);
3154-
3155- query.set_int(":sync_music", dp.sync_music ? 1 : 0);
3156- query.set_int(":sync_podcasts", dp.sync_podcasts ? 1 : 0);
3157- query.set_int(":sync_audiobooks", dp.sync_audiobooks ? 1 : 0);
3158-
3159- query.set_int(":sync_all_music", dp.sync_all_music ? 1 : 0);
3160- query.set_int(":sync_all_podcasts", dp.sync_all_podcasts ? 1 : 0);
3161- query.set_int(":sync_all_audiobooks", dp.sync_all_audiobooks ? 1 : 0);
3162-
3163- string music_playlist = "";
3164- string podcast_playlist = "";
3165- string audiobook_playlist = "";
3166-
3167- if (dp.music_playlist != null)
3168- music_playlist = dp.music_playlist.name;
3169- if (dp.podcast_playlist != null)
3170- podcast_playlist = dp.podcast_playlist.name;
3171- if (dp.audiobook_playlist != null)
3172- audiobook_playlist = dp.audiobook_playlist.name;
3173-
3174- query.set_string(":music_playlist", music_playlist);
3175- query.set_string(":podcast_playlist", podcast_playlist);
3176- query.set_string(":audiobook_playlist", audiobook_playlist);
3177- query.set_int(":last_sync_time", dp.last_sync_time);
3178-
3179- query.execute();
3180-
3181- transaction.commit();
3182- }
3183- catch(SQLHeavy.Error err) {
3184- warning ("Could not save device: %s\n", err.message);
3185- }
3186- }
3187-
3188- public void remove_device (DevicePreferences device) {
3189- assert (database != null);
3190- try {
3191- transaction = database.begin_transaction();
3192- Query query = transaction.prepare("""DELETE FROM `devices` WHERE unique_id=:unique_id""");
3193-
3194- query.set_string(":unique_id", device.id);
3195- query.execute();
3196-
3197- transaction.commit();
3198- }
3199- catch (SQLHeavy.Error err) {
3200- warning ("Could not remove smart playlist from db: %s\n", err.message);
3201- }
3202- }
3203-}
3204
3205=== removed file 'src/DataBase/DataBaseUpdater.vala'
3206--- src/DataBase/DataBaseUpdater.vala 2015-02-26 16:44:26 +0000
3207+++ src/DataBase/DataBaseUpdater.vala 1970-01-01 00:00:00 +0000
3208@@ -1,87 +0,0 @@
3209-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
3210-/*-
3211- * Copyright (c) 2012 Noise Developers (http://launchpad.net/noise)
3212- *
3213- * This software is licensed under the GNU General Public License
3214- * (version 2 or later). See the COPYING file in this distribution.
3215- *
3216- * The Noise authors hereby grant permission for non-GPL compatible
3217- * GStreamer plugins to be used and distributed together with GStreamer
3218- * and Noise. This permission is above and beyond the permissions granted
3219- * by the GPL license by which Noise is covered. If you modify this code
3220- * you may extend this exception to your version of the code, but you are not
3221- * obligated to do so. If you do not wish to do so, delete this exception
3222- * statement from your version.
3223- *
3224- * Authored by: Scott Ringwelski <sgringwe@mtu.edu>,
3225- * Victor Eduardo <victoreduardm@gmail.com>
3226- */
3227-
3228-public class Noise.DataBaseUpdater : Object {
3229-
3230- private Gee.LinkedList<Object> to_remove;
3231-
3232- public DataBaseUpdater () {
3233-
3234- to_remove = new Gee.LinkedList<Object> ();
3235-
3236- // Save on a regular basis and before exit
3237- var app = (Noise.App) GLib.Application.get_default ();
3238- app.shutdown.connect_after (() => on_close_ui_save ());
3239- app.shutdown.connect_after (update_db_sync);
3240- }
3241-
3242- public async void removeItem (Object item) {
3243- if (!to_remove.contains (item))
3244- to_remove.offer (item);
3245-
3246- update_db_sync ();
3247- }
3248-
3249- private void update_db_sync () {
3250- var dbm = DataBaseManager.get_default ();
3251- for (Object? next = to_remove.poll (); next != null; next = to_remove.poll ()) {
3252- if (next is Gee.Collection) {
3253- dbm.remove_media (next as Gee.Collection<Media>);
3254- } else if (next is StaticPlaylist) {
3255- dbm.remove_playlist (next as StaticPlaylist);
3256- dbm.remove_columns_state (next as StaticPlaylist, null);
3257- } else if (next is SmartPlaylist) {
3258- dbm.remove_smart_playlist (next as SmartPlaylist);
3259- dbm.remove_columns_state (null, next as SmartPlaylist);
3260- } else
3261- assert_not_reached ();
3262- }
3263- }
3264-
3265- private bool on_close_ui_save () {
3266- var playlists_and_queue = new Gee.TreeSet<StaticPlaylist> ();
3267- playlists_and_queue.add_all (libraries_manager.local_library.get_playlists ());
3268-
3269- playlists_and_queue.add (((LocalLibrary)libraries_manager.local_library).p_music);
3270-
3271- debug ("-- Saving columns state preferences DB.");
3272-
3273- var dbm = DataBaseManager.get_default ();
3274- dbm.save_playlist (((LocalLibrary)libraries_manager.local_library).p_music);
3275- dbm.save_columns_state (playlists_and_queue, libraries_manager.local_library.get_smart_playlists ());
3276-
3277- debug ("-- Finished columns state preferences DB.");
3278-
3279- return true;
3280- }
3281- // If the name of the playlist changed, it provides the old name to remove it from database
3282- public void save_device (DevicePreferences device) {
3283- DataBaseManager.get_default ().save_device (device);
3284- }
3285-
3286- // If the name of the playlist changed, it provides the old name to remove it from database
3287- public void save_playlist (StaticPlaylist p, string? old_name = null) {
3288- DataBaseManager.get_default ().save_playlist (p, old_name);
3289- }
3290-
3291- // If the name of the playlist changed, it provides the old name to remove it from database
3292- public void save_smart_playlist (SmartPlaylist p, string? old_name = null) {
3293- DataBaseManager.get_default ().save_smart_playlist (p, old_name);
3294- }
3295-}
3296
3297=== modified file 'src/Dialogs/FileNotFoundDialog.vala'
3298--- src/Dialogs/FileNotFoundDialog.vala 2015-06-12 13:43:45 +0000
3299+++ src/Dialogs/FileNotFoundDialog.vala 2015-08-27 10:21:27 +0000
3300@@ -118,7 +118,7 @@
3301
3302 void locate_media_clicked () {
3303 Media m = media_list.get (0);
3304- int media_id = m.rowid;
3305+ int64 media_id = m.rowid;
3306
3307 string file = "";
3308 var file_chooser = new Gtk.FileChooserDialog (_("Choose Music Folder"), this,
3309
3310=== modified file 'src/Dialogs/MediaEditor.vala'
3311--- src/Dialogs/MediaEditor.vala 2015-06-12 13:43:45 +0000
3312+++ src/Dialogs/MediaEditor.vala 2015-08-27 10:21:27 +0000
3313@@ -38,8 +38,8 @@
3314 public class Noise.MediaEditor : Gtk.Dialog {
3315 LyricFetcher lf;
3316
3317- Gee.LinkedList<int> _allMedias = new Gee.LinkedList<int> ();
3318- Gee.LinkedList<int> _medias = new Gee.LinkedList<int> ();
3319+ Gee.LinkedList<int64?> _allMedias = new Gee.LinkedList<int64?> ();
3320+ Gee.LinkedList<int64?> _medias = new Gee.LinkedList<int64?> ();
3321
3322 //for padding around notebook mostly
3323 Gtk.Stack stack;
3324@@ -53,9 +53,9 @@
3325 private Gtk.Label lyricsInfobarLabel;
3326 private Library library;
3327
3328- public signal void medias_saved (Gee.Collection<int> medias);
3329+ public signal void medias_saved (Gee.Collection<int64?> medias);
3330
3331- public MediaEditor (Gee.Collection<int> allMedias, Gee.Collection<int> medias, Library library) {
3332+ public MediaEditor (Gee.Collection<int64?> allMedias, Gee.Collection<int64?> medias, Library library) {
3333 this.library = library;
3334 this.window_position = Gtk.WindowPosition.CENTER;
3335 this.type_hint = Gdk.WindowTypeHint.DIALOG;
3336@@ -64,16 +64,16 @@
3337 this.destroy_with_parent = true;
3338 this.resizable = false;
3339 this.deletable = false;
3340-
3341+
3342 this.set_size_request (520, -1);
3343
3344 lf = new LyricFetcher();
3345-
3346+
3347 _allMedias.add_all (allMedias);
3348 _medias.add_all (medias);
3349-
3350+
3351 stack = new Gtk.Stack ();
3352-
3353+
3354 var stack_switcher = new Gtk.StackSwitcher ();
3355 stack_switcher.set_stack (stack);
3356 stack_switcher.halign = Gtk.Align.CENTER;
3357@@ -104,8 +104,9 @@
3358 buttons.set_child_secondary (arrows, true);
3359
3360 var main_grid = new Gtk.Grid ();
3361- main_grid.attach (stack, 0, 0, 1, 1);
3362- main_grid.attach (buttons, 0, 1, 1, 1);
3363+ main_grid.attach (stack_switcher, 0, 0, 1, 1);
3364+ main_grid.attach (stack, 0, 1, 1, 1);
3365+ main_grid.attach (buttons, 0, 2, 1, 1);
3366
3367 var content = get_content_area () as Gtk.Container;
3368 content.margin_left = content.margin_right = 12;
3369@@ -133,7 +134,7 @@
3370 Media sum = library.media_from_id(_medias.get(0)).copy();
3371
3372 /** find what these media have what common, and keep those values **/
3373- foreach(int i in _medias) {
3374+ foreach (int64 i in _medias) {
3375 Media s = library.media_from_id(i);
3376
3377 if(s.track != sum.track)
3378@@ -294,13 +295,12 @@
3379 });
3380 }
3381
3382-
3383 public void previousClicked() {
3384 save_medias();
3385
3386 // now fetch the next media on current_view
3387- int i = 0; // will hold next media to edit
3388- int indexOfCurrentFirst = _allMedias.index_of(_medias.get(0));
3389+ int64 i = 0; // will hold next media to edit
3390+ int indexOfCurrentFirst = _allMedias.index_of(_medias.first ());
3391
3392 if(indexOfCurrentFirst == 0)
3393 i = _allMedias.get(_allMedias.size - 1);
3394@@ -308,7 +308,7 @@
3395 i = _allMedias.get(indexOfCurrentFirst - 1);
3396
3397 // now fetch the previous media on current_view
3398- var newMedias = new Gee.LinkedList<int>();
3399+ var newMedias = new Gee.LinkedList<int64?> ();
3400 newMedias.add(i);
3401
3402 change_media(newMedias);
3403@@ -318,21 +318,21 @@
3404 save_medias();
3405
3406 // now fetch the next media on current_view
3407- int i = 0; // will hold next media to edit
3408+ int64 i = 0; // will hold next media to edit
3409 int indexOfCurrentLast = _allMedias.index_of(_medias.get(_medias.size - 1));
3410
3411 if(indexOfCurrentLast == _allMedias.size - 1)
3412- i = _allMedias.get(0);
3413+ i = _allMedias.first ();
3414 else
3415 i = _allMedias.get(indexOfCurrentLast + 1);
3416
3417- var newMedias = new Gee.LinkedList<int>();
3418+ var newMedias = new Gee.LinkedList<int64?>();
3419 newMedias.add(i);
3420
3421 change_media(newMedias);
3422 }
3423
3424- public void change_media(Gee.LinkedList<int> newMedias) {
3425+ public void change_media(Gee.LinkedList<int64?> newMedias) {
3426 _medias = newMedias;
3427
3428 Media sum = library.media_from_id(newMedias.get(0));
3429@@ -376,8 +376,8 @@
3430 }
3431
3432 public void save_medias() {
3433- foreach(int i in _medias) {
3434- Media s = library.media_from_id(i);
3435+ foreach (int64 i in _medias) {
3436+ Media s = library.media_from_id (i);
3437
3438 if(fields.get("Title").checked())
3439 s.title = fields.get("Title").get_value();
3440
3441=== modified file 'src/Dialogs/SmartPlaylistEditor.vala'
3442--- src/Dialogs/SmartPlaylistEditor.vala 2015-06-12 13:43:45 +0000
3443+++ src/Dialogs/SmartPlaylistEditor.vala 2015-08-27 10:21:27 +0000
3444@@ -208,9 +208,10 @@
3445
3446 public virtual void save_click () {
3447 sp.clear_queries ();
3448- var queries = new Gee.LinkedList<SmartQuery> ();
3449+ var queries = new Gee.TreeSet<SmartQuery> ();
3450 foreach (SmartPlaylistEditorQuery speq in queries_list) {
3451- queries.add (speq.get_query ());
3452+ var query = speq.get_query ();
3453+ queries.add (query);
3454 }
3455
3456 sp.add_queries (queries);
3457@@ -265,7 +266,6 @@
3458 field_combobox.append_text (_("Comment"));
3459 field_combobox.append_text (_("Composer"));
3460 field_combobox.append_text (_("Date Added"));
3461- field_combobox.append_text (_("Date Released"));
3462 field_combobox.append_text (_("Genre"));
3463 field_combobox.append_text (_("Grouping"));
3464 field_combobox.append_text (_("Last Played"));
3465@@ -281,11 +281,11 @@
3466 comparator_combobox.set_active ((int)q.comparator);
3467
3468 if (needs_value (q.field)) {
3469- value_entry.text = q.value;
3470+ value_entry.text = q.value.get_string ();
3471 } else if (q.field == SmartQuery.FieldType.RATING) {
3472- _valueRating.rating = int.parse (q.value);
3473+ _valueRating.rating = q.value.get_int ();
3474 } else {
3475- _valueNumerical.set_value (int.parse (q.value));
3476+ _valueNumerical.set_value (q.value.get_int ());
3477 }
3478
3479 _units = new Gtk.Label ("");
3480@@ -308,16 +308,23 @@
3481 }
3482
3483 public SmartQuery get_query () {
3484- SmartQuery rv = new SmartQuery ();
3485+ var rv = new SmartQuery ();
3486
3487 rv.field = (SmartQuery.FieldType)field_combobox.get_active ();
3488 rv.comparator = comparators.get (comparator_combobox.get_active ());
3489- if (needs_value ((SmartQuery.FieldType)field_combobox.get_active ()))
3490- rv.value = value_entry.text;
3491- else if (field_combobox.get_active () == SmartQuery.FieldType.RATING)
3492- rv.value = _valueRating.rating.to_string ();
3493- else
3494- rv.value = _valueNumerical.value.to_string ();
3495+ if (needs_value ((SmartQuery.FieldType)field_combobox.get_active ())) {
3496+ var value = Value (typeof (string));
3497+ value.set_string (value_entry.text);
3498+ rv.value = value;
3499+ } else if (field_combobox.get_active () == SmartQuery.FieldType.RATING) {
3500+ var value = Value (typeof (int));
3501+ value.set_int (_valueRating.rating);
3502+ rv.value = value;
3503+ } else {
3504+ var value = Value (typeof (int));
3505+ value.set_int ((int)_valueNumerical.value);
3506+ rv.value = value;
3507+ }
3508
3509 return rv;
3510 }
3511@@ -437,7 +444,6 @@
3512 }
3513
3514 public bool is_date (SmartQuery.FieldType compared) {
3515- return (compared == SmartQuery.FieldType.LAST_PLAYED || compared == SmartQuery.FieldType.DATE_ADDED
3516- || compared == SmartQuery.FieldType.DATE_RELEASED);
3517+ return (compared == SmartQuery.FieldType.LAST_PLAYED || compared == SmartQuery.FieldType.DATE_ADDED);
3518 }
3519 }
3520
3521=== modified file 'src/FileOperator.vala'
3522--- src/FileOperator.vala 2015-05-24 21:46:00 +0000
3523+++ src/FileOperator.vala 2015-08-27 10:21:27 +0000
3524@@ -309,7 +309,7 @@
3525 App.main_window.show_notification (_("Import Complete"), _("%s has imported your library.").printf (((Noise.App) GLib.Application.get_default ()).get_name ()));
3526
3527 if (import_type == ImportType.PLAYLIST) {
3528- var to_add = new Gee.LinkedList<int> ();
3529+ var to_add = new Gee.LinkedList<int64?> ();
3530 foreach (var s in all_new_imports)
3531 to_add.add (s.rowid);
3532 new_playlist.add_medias (to_add);
3533
3534=== modified file 'src/LibraryWindow.vala'
3535--- src/LibraryWindow.vala 2015-06-12 16:10:33 +0000
3536+++ src/LibraryWindow.vala 2015-08-27 10:21:27 +0000
3537@@ -78,7 +78,6 @@
3538 private Gee.HashMap<unowned Playlist, int> match_playlists;
3539 private Gee.HashMap<string, int> match_devices;
3540 private Gee.HashMap<unowned Playlist, SourceListEntry> match_playlist_entry;
3541- private Gee.HashMap<Playlist, TreeViewSetup> match_tvs;
3542
3543 public LibraryWindow () {
3544 headerbar = new Gtk.HeaderBar ();
3545@@ -124,8 +123,10 @@
3546 match_playlists = new Gee.HashMap<unowned Playlist, int> ();
3547 match_devices = new Gee.HashMap<string, int> ();
3548 match_playlist_entry = new Gee.HashMap<unowned Playlist, SourceListEntry> ();
3549- match_tvs = new Gee.HashMap<Playlist, TreeViewSetup> ();
3550
3551+ libraries_manager.add_headless_playlist.connect ((playlist) => {
3552+ add_playlist (playlist);
3553+ });
3554
3555 // init some booleans
3556 if (this.library_manager.get_medias ().size > 0) {
3557@@ -340,7 +341,7 @@
3558
3559 public void connect_to_sourcelist_signals () {
3560
3561- source_list_view.selection_changed.connect ( (page_number) => {
3562+ source_list_view.selection_changed.connect ((page_number) => {
3563 view_container.set_current_view_from_index (page_number);
3564 });
3565
3566@@ -348,7 +349,7 @@
3567 search_field_has_focus = false;
3568 });
3569
3570- source_list_view.item_action_activated.connect ( (page_number) => {
3571+ source_list_view.item_action_activated.connect ((page_number) => {
3572 var view = view_container.get_view (page_number);
3573 if (view is DeviceView) {
3574 ((DeviceView)view).d.eject();
3575@@ -356,7 +357,7 @@
3576 });
3577 source_list_view.edited.connect (playlist_name_edited);
3578
3579- source_list_view.playlist_rename_clicked.connect ( (page_number) => {
3580+ source_list_view.playlist_rename_clicked.connect ((page_number) => {
3581 var view = view_container.get_view (page_number);
3582 if (view is PlaylistViewWrapper) {
3583 search_field_has_focus = false;
3584@@ -364,26 +365,29 @@
3585 }
3586 });
3587
3588- source_list_view.playlist_edit_clicked.connect ( (page_number) => {
3589+ source_list_view.playlist_edit_clicked.connect ((page_number) => {
3590 var view = view_container.get_view (page_number);
3591 if (view is PlaylistViewWrapper) {
3592- show_smart_playlist_dialog(library_manager.smart_playlist_from_id(((PlaylistViewWrapper)view).playlist_id));
3593+ var p = ((PlaylistViewWrapper)view).playlist;
3594+ if (p is SmartPlaylist) {
3595+ show_smart_playlist_dialog ((SmartPlaylist) p);
3596+ }
3597 }
3598 });
3599
3600- source_list_view.playlist_remove_clicked.connect ( (page_number) => {
3601+ source_list_view.playlist_remove_clicked.connect ((page_number) => {
3602 var view = view_container.get_view (page_number);
3603 if (view is PlaylistViewWrapper) {
3604 var playlistview = (PlaylistViewWrapper)view;
3605 if (playlistview.hint == ViewWrapper.Hint.PLAYLIST) {
3606- ((ViewWrapper)view).library.remove_playlist(playlistview.playlist_id);
3607+ playlistview.library.remove_playlist (playlistview.playlist.rowid);
3608 } else if (playlistview.hint == ViewWrapper.Hint.SMART_PLAYLIST) {
3609- ((ViewWrapper)view).library.remove_smart_playlist(playlistview.playlist_id);
3610+ playlistview.library.remove_smart_playlist (playlistview.playlist.rowid);
3611 }
3612 }
3613 });
3614
3615- source_list_view.device_import_clicked.connect ( (page_number) => {
3616+ source_list_view.device_import_clicked.connect ((page_number) => {
3617 foreach (var device in DeviceManager.get_default ().get_initialized_devices ()) {
3618 if(page_number == match_devices.get (device.get_unique_identifier())) {
3619 libraries_manager.transfer_to_local_library (device.get_library().get_medias ());
3620@@ -392,7 +396,7 @@
3621 }
3622 });
3623
3624- source_list_view.device_new_playlist_clicked.connect ( (page_number) => {
3625+ source_list_view.device_new_playlist_clicked.connect ((page_number) => {
3626 foreach (var device in DeviceManager.get_default ().get_initialized_devices ()) {
3627 if(page_number == match_devices.get (device.get_unique_identifier())) {
3628 create_new_playlist (device.get_library());
3629@@ -401,7 +405,7 @@
3630 }
3631 });
3632
3633- source_list_view.device_sync_clicked.connect ( (page_number) => {
3634+ source_list_view.device_sync_clicked.connect ((page_number) => {
3635 foreach (var device in DeviceManager.get_default ().get_initialized_devices ()) {
3636 if(page_number == match_devices.get (device.get_unique_identifier())) {
3637 device.synchronize ();
3638@@ -410,7 +414,7 @@
3639 }
3640 });
3641
3642- source_list_view.device_eject_clicked.connect ( (page_number) => {
3643+ source_list_view.device_eject_clicked.connect ((page_number) => {
3644 foreach (var device in DeviceManager.get_default ().get_initialized_devices ()) {
3645 if(page_number == match_devices.get (device.get_unique_identifier())) {
3646 device.eject();
3647@@ -419,25 +423,25 @@
3648 }
3649 });
3650
3651- source_list_view.playlist_remove_clicked.connect ( (page_number) => {
3652+ source_list_view.playlist_remove_clicked.connect ((page_number) => {
3653 var view = view_container.get_view (page_number);
3654 if (view is PlaylistViewWrapper) {
3655 var playlistview = (PlaylistViewWrapper)view;
3656 if (playlistview.hint == ViewWrapper.Hint.PLAYLIST) {
3657- ((ViewWrapper)view).library.remove_playlist(playlistview.playlist_id);
3658+ playlistview.library.remove_playlist (playlistview.playlist.rowid);
3659 } else if (playlistview.hint == ViewWrapper.Hint.SMART_PLAYLIST) {
3660- ((ViewWrapper)view).library.remove_smart_playlist(playlistview.playlist_id);
3661+ playlistview.library.remove_smart_playlist (playlistview.playlist.rowid);
3662 }
3663 }
3664 });
3665
3666- source_list_view.playlist_save_clicked.connect ( (page_number) => {
3667+ source_list_view.playlist_save_clicked.connect ((page_number) => {
3668 var view = view_container.get_view (page_number);
3669 if (view is PlaylistViewWrapper) {
3670 var playlistview = (PlaylistViewWrapper)view;
3671 if (playlistview.hint != ViewWrapper.Hint.READ_ONLY_PLAYLIST)
3672 return;
3673- var playlist = library_manager.playlist_from_id (playlistview.playlist_id);
3674+ var playlist = playlistview.playlist;
3675 if (playlist != null) {
3676 var new_playlist = new StaticPlaylist ();
3677 new_playlist.name = PlaylistsUtils.get_new_playlist_name (library_manager.get_playlists (), playlist.name);
3678@@ -447,29 +451,29 @@
3679 }
3680 });
3681
3682- source_list_view.playlist_export_clicked.connect ( (page_number) => {
3683+ source_list_view.playlist_export_clicked.connect ((page_number) => {
3684 var view = view_container.get_view (page_number);
3685 if (view is PlaylistViewWrapper) {
3686 var playlistview = (PlaylistViewWrapper)view;
3687 switch (playlistview.hint) {
3688 case ViewWrapper.Hint.PLAYLIST:
3689 case ViewWrapper.Hint.READ_ONLY_PLAYLIST:
3690- PlaylistsUtils.export_playlist (((ViewWrapper)view).library.playlist_from_id (playlistview.playlist_id));
3691+ PlaylistsUtils.export_playlist (playlistview.playlist);
3692 break;
3693 case ViewWrapper.Hint.SMART_PLAYLIST:
3694- PlaylistsUtils.export_playlist (((ViewWrapper)view).library.smart_playlist_from_id (playlistview.playlist_id));
3695+ PlaylistsUtils.export_playlist (playlistview.playlist);
3696 break;
3697 }
3698 }
3699 });
3700
3701- source_list_view.playlist_media_added.connect ( (page_number, uris) => {
3702+ source_list_view.playlist_media_added.connect ((page_number, uris) => {
3703 var view = view_container.get_view (page_number);
3704 if (view is PlaylistViewWrapper) {
3705 var playlistview = (PlaylistViewWrapper) view;
3706 if (playlistview.hint == ViewWrapper.Hint.PLAYLIST) {
3707 var library = playlistview.library;
3708- var playlist = library.playlist_from_id (playlistview.playlist_id);
3709+ var playlist = playlistview.playlist;
3710 if (playlist == null)
3711 return;
3712
3713@@ -508,18 +512,21 @@
3714 viewSelector.selected = (Widgets.ViewSelector.Mode) Settings.SavedState.get_default ().view_mode;
3715
3716 initialization_finished = true;
3717-
3718+
3719 // Set the focus on the current view
3720- if (main_settings.last_playlist_playing != -1) {
3721- for (int i =0; i< view_container.get_n_pages (); i++) {
3722- var parent = view_container.get_nth_page (i) as ViewWrapper;
3723- if (parent.relative_id == main_settings.last_playlist_playing) {
3724- if (parent.hint == Noise.ViewWrapper.Hint.PLAYLIST || parent.hint == Noise.ViewWrapper.Hint.READ_ONLY_PLAYLIST)
3725- show_playlist_view (libraries_manager.local_library.playlist_from_id (parent.relative_id));
3726- else if (parent.hint == Noise.ViewWrapper.Hint.SMART_PLAYLIST)
3727- show_playlist_view (libraries_manager.local_library.smart_playlist_from_id (parent.relative_id));
3728- break;
3729- }
3730+ if (main_settings.last_playlist_playing != "") {
3731+ Playlist? p = null;
3732+ if (main_settings.last_playlist_playing.contains ("s")) {
3733+ int64 rowid = int64.parse (main_settings.last_playlist_playing.replace ("s", ""));
3734+ p = library_manager.smart_playlist_from_id (rowid);
3735+ } else {
3736+ int64 rowid = int64.parse (main_settings.last_playlist_playing.replace ("p", ""));
3737+ p = library_manager.playlist_from_id (rowid);
3738+ }
3739+
3740+ if (p != null) {
3741+ show_playlist_view (p);
3742+ } else {
3743 show_playlist_view (library_manager.p_music);
3744 }
3745 } else {
3746@@ -534,17 +541,17 @@
3747 searchField.activate.connect (searchFieldActivate);
3748 searchField.search_changed.connect (() => {if (searchField.text_length != 1) libraries_manager.search_for_string (searchField.get_text ());});
3749 searchField.text = main_settings.search_string;
3750- libraries_manager.search_for_string (main_settings.search_string);
3751
3752 debug ("DONE WITH USER INTERFACE");
3753
3754- int last_playing_id = main_settings.last_media_playing;
3755-
3756- if (last_playing_id > 0) {
3757+ int64 last_playing_id = main_settings.last_media_playing;
3758+ if (last_playing_id >= 0) {
3759 var last_playing_media = library_manager.media_from_id (last_playing_id);
3760- if (last_playing_media != null && last_playing_media.file.query_exists ())
3761+ if (last_playing_media != null && last_playing_media.file.query_exists ()) {
3762 App.player.playMedia (last_playing_media, true);
3763+ }
3764 }
3765+ libraries_manager.search_for_string (Settings.Main.get_default ().search_string);
3766 }
3767
3768 /**
3769@@ -655,36 +662,20 @@
3770
3771 private void load_playlists () {
3772 debug ("Loading playlists");
3773-
3774- library_manager.add_playlist (App.player.queue_playlist);
3775- library_manager.add_playlist (App.player.history_playlist);
3776-
3777- match_tvs.set_all (DataBaseManager.get_default ().load_columns_state ());
3778-
3779+
3780 foreach (SmartPlaylist p in library_manager.get_smart_playlists()) {
3781 add_smartplaylist (p);
3782 }
3783
3784 foreach (StaticPlaylist p in library_manager.get_playlists()) {
3785- if (p.name != App.player.queue_playlist.name && p.name != App.player.history_playlist.name)
3786- add_playlist (p);
3787- }
3788-
3789- TreeViewSetup? music_tvs = null;
3790- foreach (var entry in match_tvs.entries) {
3791- if (entry.key.name == MUSIC_PLAYLIST) {
3792- music_tvs = entry.value;
3793- music_tvs.set_hint (ViewWrapper.Hint.MUSIC);
3794- break;
3795- }
3796- }
3797- if (music_tvs == null) {
3798- music_tvs = new TreeViewSetup (ListColumn.ARTIST,
3799- Gtk.SortType.ASCENDING,
3800- ViewWrapper.Hint.MUSIC);
3801- match_tvs.set (library_manager.p_music, music_tvs);
3802- }
3803+ add_playlist (p);
3804+ }
3805+
3806+ libraries_manager.add_headless_playlist (App.player.queue_playlist);
3807+ libraries_manager.add_headless_playlist (App.player.history_playlist);
3808+
3809 // Add Music Library View
3810+ var music_tvs = new TreeViewSetup (ViewWrapper.Hint.MUSIC, "library:main", library_manager.connection);
3811 var music_view_wrapper = new MusicViewWrapper (music_tvs, library_manager, topDisplay);
3812 int view_number = view_container.add_view (music_view_wrapper);
3813 var entry = source_list_view.add_item (view_number, _("Music"), ViewWrapper.Hint.MUSIC, new ThemedIcon ("library-music"));
3814@@ -772,20 +763,22 @@
3815 match_devices.unset (device.get_unique_identifier());
3816 remove_view_and_update (page_number);
3817 }
3818-
3819+
3820 private void create_device_source_list (Device d) {
3821 lock (match_devices) {
3822 SourceListEntry? entry;
3823- var dv = new DeviceView (d);
3824+ var pref = library_manager.get_preferences_for_device (d);
3825+ var dv = new DeviceView (d, pref);
3826 int view_number = view_container.add_view (dv);
3827- match_devices.set (d.get_unique_identifier(), view_number);
3828- if(d.only_use_custom_view()) {
3829+ match_devices.set (d.get_unique_identifier (), view_number);
3830+ if (d.only_use_custom_view ()) {
3831 message("new custom device (probably a CD) added with %d songs.\n", d.get_library ().get_medias().size);
3832
3833 entry = source_list_view.add_item (view_number, d.getDisplayName(), ViewWrapper.Hint.DEVICE, d.get_icon(), new ThemedIcon ("media-eject-symbolic"), null, d);
3834 } else {
3835 debug ("adding device view with %d\n", d.get_library ().get_medias().size);
3836- var music_view_wrapper = new DeviceViewWrapper(new TreeViewSetup(ListColumn.ARTIST, Gtk.SortType.ASCENDING, ViewWrapper.Hint.DEVICE_AUDIO), d, d.get_library ());
3837+ var tvs = new TreeViewSetup (ViewWrapper.Hint.DEVICE_AUDIO);
3838+ var music_view_wrapper = new DeviceViewWrapper(tvs, d, d.get_library ());
3839
3840 int subview_number = view_container.add_view (music_view_wrapper);
3841 entry = source_list_view.add_item (view_number, d.getDisplayName(), ViewWrapper.Hint.DEVICE, d.get_icon(), new ThemedIcon ("media-eject-symbolic"), null, d);
3842@@ -825,10 +818,6 @@
3843 library.add_playlist(playlist);
3844 }
3845
3846- public TreeViewSetup? get_treeviewsetup_from_playlist (Playlist p) {
3847- return match_tvs.get (p);
3848- }
3849-
3850 public void show_playlist_view (Playlist p) {
3851 if (match_playlists.has_key (p)) {
3852 source_list_view.selected = match_playlist_entry.get (p);
3853@@ -837,46 +826,40 @@
3854 }
3855
3856 private void create_playlist_source_list (StaticPlaylist p, SourceListExpandableItem? into_expandable = null, Library? library = library_manager) {
3857- SourceListEntry? entry;
3858- int view_number;
3859- if (p.read_only == false) {
3860- var view = new PlaylistViewWrapper (p.rowid, ViewWrapper.Hint.PLAYLIST, null, library);
3861- view_number = view_container.add_view (view);
3862- entry = source_list_view.add_item (view_number, p.name, ViewWrapper.Hint.PLAYLIST, p.icon, null, into_expandable);
3863+ ViewWrapper.Hint hint = ViewWrapper.Hint.PLAYLIST;
3864+ if (p.read_only == true) {
3865+ hint = ViewWrapper.Hint.READ_ONLY_PLAYLIST;
3866+ }
3867+
3868+ TreeViewSetup? tvs = null;
3869+ if (p is LocalStaticPlaylist) {
3870+ tvs = new TreeViewSetup (hint, "library:p%lld".printf (p.rowid), library_manager.connection);
3871+ } else if (p == App.player.queue_playlist) {
3872+ tvs = new TreeViewSetup (hint, "library:queue", library_manager.connection);
3873+ } else if (p == App.player.history_playlist) {
3874+ tvs = new TreeViewSetup (hint, "library:history", library_manager.connection);
3875 } else {
3876- if (p.name == C_("Name of the playlist", "Queue")) {
3877- var queue_view = new PlaylistViewWrapper (App.player.queue_playlist.rowid, ViewWrapper.Hint.READ_ONLY_PLAYLIST,
3878- match_tvs.get (App.player.queue_playlist), library);
3879- queue_view.set_no_media_alert_message (_("No songs in Queue"),
3880- _("To add songs to the queue, use the <b>secondary click</b> on an item and choose <b>Queue</b>. When a song finishes, the queued songs will be played first before the next song in the currently playing list."));
3881- view_number = view_container.add_view (queue_view);
3882- entry = source_list_view.add_item (view_number, App.player.queue_playlist.name,
3883- ViewWrapper.Hint.READ_ONLY_PLAYLIST, new ThemedIcon ("playlist-queue"));
3884- update_badge_on_playlist_update (p, entry);
3885- App.player.queue_media (p.medias);
3886- } else if (p.name == _("History")) {
3887- var history_view = new PlaylistViewWrapper (App.player.history_playlist.rowid, ViewWrapper.Hint.READ_ONLY_PLAYLIST,
3888- match_tvs.get(App.player.history_playlist), library);
3889- history_view.set_no_media_alert_message (_("No songs in History"),
3890- _("After a part of a song has been played, it is added to the history list.\nYou can use this list to see all the songs you have played during the current session."));
3891- view_number = view_container.add_view (history_view);
3892- entry = source_list_view.add_item (view_number, App.player.history_playlist.name,
3893- ViewWrapper.Hint.READ_ONLY_PLAYLIST, new ThemedIcon ("document-open-recent"));
3894- App.player.history_playlist.add_medias (p.medias);
3895- } else {
3896- var view = new PlaylistViewWrapper (p.rowid, ViewWrapper.Hint.READ_ONLY_PLAYLIST, match_tvs.get(p), library);
3897- view_number = view_container.add_view (view);
3898- entry = source_list_view.add_item (view_number, p.name, ViewWrapper.Hint.READ_ONLY_PLAYLIST, p.icon, null, into_expandable);
3899- if (p.show_badge == true) {
3900- update_badge_on_playlist_update (p, entry);
3901- }
3902- }
3903- }
3904- lock (match_playlists) {
3905- match_playlist_entry.set (p, entry);
3906- match_playlists.set (p, view_number);
3907- }
3908- if (newly_created_playlist == true) {
3909+ tvs = new TreeViewSetup (hint);
3910+ }
3911+
3912+ var view = new PlaylistViewWrapper (p, hint, tvs, library);
3913+ var view_number = view_container.add_view (view);
3914+ var entry = source_list_view.add_item (view_number, p.name, hint, p.icon, null, into_expandable);
3915+ if (p.show_badge == true) {
3916+ update_badge_on_playlist_update (p, entry);
3917+ }
3918+
3919+ if (p == App.player.queue_playlist) {
3920+ view.set_no_media_alert_message (_("No songs in Queue"), _("To add songs to the queue, use the <b>secondary click</b> on an item and choose <b>Queue</b>. When a song finishes, the queued songs will be played first before the next song in the currently playing list."));
3921+ App.player.queue_media (p.medias);
3922+ } else if (p == App.player.history_playlist) {
3923+ view.set_no_media_alert_message (_("No songs in History"), _("After a part of a song has been played, it is added to the history list.\nYou can use this list to see all the songs you have played during the current session."));
3924+ }
3925+
3926+ match_playlist_entry.set (p, entry);
3927+ match_playlists.set (p, view_number);
3928+
3929+ if (newly_created_playlist == true && p.read_only == false) {
3930 newly_created_playlist = false;
3931 show_playlist_view (p);
3932
3933@@ -925,24 +908,34 @@
3934 }
3935 }
3936 }
3937+
3938 private void create_smartplaylist_source_list (SmartPlaylist p, SourceListExpandableItem? into_expandable = null, Library? library = library_manager) {
3939- SourceListEntry? entry;
3940- int view_number;
3941-
3942- var view = new PlaylistViewWrapper (p.rowid, ViewWrapper.Hint.SMART_PLAYLIST, match_tvs.get(p), library_manager);
3943- view.button_clicked.connect ((playlist_id) => {
3944- show_smart_playlist_dialog(library_manager.smart_playlist_from_id(playlist_id));
3945+ TreeViewSetup? tvs = null;
3946+ if (p is LocalSmartPlaylist) {
3947+ tvs = new TreeViewSetup (ViewWrapper.Hint.SMART_PLAYLIST, "library:s%lld".printf (p.rowid), library_manager.connection);
3948+ } else {
3949+ tvs = new TreeViewSetup (ViewWrapper.Hint.SMART_PLAYLIST);
3950+ }
3951+
3952+ var view = new PlaylistViewWrapper (p, ViewWrapper.Hint.SMART_PLAYLIST, tvs, library_manager);
3953+ view.button_clicked.connect ((playlist) => {
3954+ if (playlist is SmartPlaylist) {
3955+ show_smart_playlist_dialog ((SmartPlaylist) playlist);
3956+ }
3957 });
3958- view_number = view_container.add_view (view);
3959- entry = source_list_view.add_item (view_number, p.name, ViewWrapper.Hint.SMART_PLAYLIST, p.icon);
3960+
3961+ var view_number = view_container.add_view (view);
3962+ var entry = source_list_view.add_item (view_number, p.name, ViewWrapper.Hint.SMART_PLAYLIST, p.icon);
3963 p.updated.connect ((old_name) => {
3964 if (old_name != null)
3965 source_list_view.change_playlist_name (match_playlists.get(p), p.name);
3966 });
3967+
3968 lock (match_playlists) {
3969 match_playlist_entry.set (p, entry);
3970 match_playlists.set (p, view_number);
3971 }
3972+
3973 if (newly_created_playlist == true) {
3974 newly_created_playlist = false;
3975 show_playlist_view (p);
3976@@ -996,7 +989,7 @@
3977 }
3978
3979
3980- public virtual void playback_stopped (int was_playing) {
3981+ public virtual void playback_stopped (int64 was_playing) {
3982 playButton.set_image (new Gtk.Image.from_icon_name ("media-playback-start-symbolic", Gtk.IconSize.LARGE_TOOLBAR));
3983 //reset some booleans
3984 tested_for_video = false;
3985@@ -1175,7 +1168,7 @@
3986 //at 30 seconds in, we consider the media as played
3987 if(sec > 30 && !media_considered_played) {
3988 media_considered_played = true;
3989- App.player.current_media.last_played = (int)time_t();
3990+ App.player.current_media.last_played = (int)time_t ();
3991
3992 library_manager.update_media (App.player.current_media, false, false);
3993
3994@@ -1185,17 +1178,6 @@
3995 temp_media.add (App.player.current_media);
3996 App.player.history_playlist.add_medias (temp_media);
3997 }
3998-
3999-#if HAVE_ZEITGEIST
4000- var event = new Zeitgeist.Event.full (Zeitgeist.ZG_ACCESS_EVENT,
4001- Zeitgeist.ZG_SCHEDULED_ACTIVITY, "app://%s".printf (App.instance.get_desktop_file_name ()),
4002- new Zeitgeist.Subject.full(App.player.current_media.uri,
4003- Zeitgeist.NFO_AUDIO,
4004- Zeitgeist.NFO_FILE_DATA_OBJECT,
4005- "text/plain", "",
4006- App.player.current_media.title, ""));
4007- new Zeitgeist.Log ().insert_events_no_reply(event);
4008-#endif
4009 }
4010
4011 if((sec/media_length > 0.50) && (media_half_played_sended == false)) {
4012
4013=== renamed file 'core/Devices/DevicePreferences.vala' => 'src/LocalBackend/DevicePreferences.vala'
4014--- core/Devices/DevicePreferences.vala 2015-06-12 13:51:08 +0000
4015+++ src/LocalBackend/DevicePreferences.vala 2015-08-27 10:21:27 +0000
4016@@ -30,24 +30,165 @@
4017 */
4018
4019 public class Noise.DevicePreferences : GLib.Object {
4020- public string id { get; construct set; }
4021-
4022- public bool sync_when_mounted { get; set; }
4023- public int last_sync_time { get; set; }
4024-
4025- public bool sync_music { get; set; default=true; }
4026- public bool sync_podcasts { get; set; default=false; }
4027- public bool sync_audiobooks { get; set; default=false; }
4028-
4029- public bool sync_all_music { get; set; default=true;}
4030- public bool sync_all_podcasts { get; set; default=true; }
4031- public bool sync_all_audiobooks { get; set; default=true; }
4032-
4033- public unowned Playlist music_playlist { get; set; }
4034- public unowned Playlist podcast_playlist { get; set; } // must only contain podcasts. if not, will ignore others
4035- public unowned Playlist audiobook_playlist { get; set; } // must only contain audiobooks. if not, will ignore others
4036-
4037- public DevicePreferences (string id) {
4038- this.id = id;
4039- }
4040+ private string id;
4041+
4042+ public bool? _sync_when_mounted = null;
4043+ public bool sync_when_mounted {
4044+ get {
4045+ common_bool_getter ("sync_when_mounted", ref _sync_when_mounted);
4046+ return _sync_when_mounted;
4047+ }
4048+ set {
4049+ common_bool_setter ("sync_when_mounted", value, ref _sync_when_mounted);
4050+ }
4051+ }
4052+
4053+ public uint? _last_sync_time = null;
4054+ public uint last_sync_time {
4055+ get {
4056+ common_uint_getter ("last_sync_time", ref _last_sync_time);
4057+ return _last_sync_time;
4058+ }
4059+ set {
4060+ common_uint_setter ("last_sync_time", value, ref _last_sync_time);
4061+ }
4062+ }
4063+
4064+ public bool? _sync_music = null;
4065+ public bool sync_music {
4066+ get {
4067+ common_bool_getter ("sync_music", ref _sync_music);
4068+ return _sync_music;
4069+ }
4070+ set {
4071+ common_bool_setter ("sync_music", value, ref _sync_music);
4072+ }
4073+ }
4074+
4075+ public bool? _sync_all_music = null;
4076+ public bool sync_all_music {
4077+ get {
4078+ common_bool_getter ("sync_all_music", ref _sync_all_music);
4079+ return _sync_all_music;
4080+ }
4081+ set {
4082+ common_bool_setter ("sync_all_music", value, ref _sync_all_music);
4083+ }
4084+ }
4085+
4086+ public Playlist? music_playlist {
4087+ owned get {
4088+ var result = query_field ("music_playlist");
4089+ if (result.type () == typeof (Gda.Null)) {
4090+ return null;
4091+ }
4092+
4093+ string playlist_string = result.get_string ();
4094+ if (playlist_string == "" || playlist_string == null)
4095+ return null;
4096+ if ("p" in playlist_string) {
4097+ playlist_string = playlist_string.replace ("p", "");
4098+ return Noise.libraries_manager.local_library.playlist_from_id (int64.parse (playlist_string));
4099+ } else {
4100+ playlist_string = playlist_string.replace ("s", "");
4101+ return Noise.libraries_manager.local_library.smart_playlist_from_id (int64.parse (playlist_string));
4102+ }
4103+ }
4104+ set {
4105+ string playlist_string = "";
4106+ if (value != null) {
4107+ if (value is StaticPlaylist) {
4108+ playlist_string = "p%lld".printf (value.rowid);
4109+ } else {
4110+ playlist_string = "s%lld".printf (value.rowid);
4111+ }
4112+ }
4113+
4114+ set_field ("music_playlist", Database.make_string_value (playlist_string));
4115+ }
4116+ }
4117+
4118+ private Gda.Connection connection;
4119+
4120+ public DevicePreferences (Noise.Device device, Gda.Connection connection) {
4121+ this.id = device.get_unique_identifier ();
4122+ this.connection = connection;
4123+ if (query_field ("sync_music") == null) {
4124+ try {
4125+ var builder = new Gda.SqlBuilder (Gda.SqlStatementType.INSERT);
4126+ builder.set_table (Database.Devices.TABLE_NAME);
4127+ builder.add_field_value_as_gvalue ("unique_id", Database.make_string_value (id));
4128+ connection.statement_execute_non_select (builder.get_statement (), null, null);
4129+ } catch (Error e) {
4130+ warning ("Could not save media: %s", e.message);
4131+ }
4132+ }
4133+ }
4134+
4135+ private uint common_uint_getter (string field, ref uint? temp) {
4136+ if (temp != null)
4137+ return temp;
4138+
4139+ var result = query_field (field);
4140+ if (result.type () == typeof (Gda.Null)) {
4141+ temp = 0;
4142+ return temp;
4143+ }
4144+
4145+ temp = (uint)result.get_int ();
4146+ return temp;
4147+ }
4148+
4149+ private void common_uint_setter (string field, uint value, ref uint? temp) {
4150+ temp = value;
4151+ set_field (field, Database.make_uint_value (value));
4152+ }
4153+
4154+ private bool common_bool_getter (string field, ref bool? temp) {
4155+ if (temp != null)
4156+ return temp;
4157+
4158+ var result = query_field (field);
4159+ if (result.type () == typeof (Gda.Null)) {
4160+ temp = false;
4161+ return temp;
4162+ }
4163+
4164+ temp = result.get_int () == 1;
4165+ return temp;
4166+ }
4167+
4168+ private void common_bool_setter (string field, bool value, ref bool? temp) {
4169+ temp = value;
4170+ set_field (field, Database.make_bool_value (value));
4171+ }
4172+
4173+ private GLib.Value? query_field (string field) {
4174+ try {
4175+ var sql = new Gda.SqlBuilder (Gda.SqlStatementType.SELECT);
4176+ sql.select_add_target (Database.Devices.TABLE_NAME, null);
4177+ sql.add_field_value_id (sql.add_id (field), 0);
4178+ var id_field = sql.add_id ("unique_id");
4179+ var id_param = sql.add_expr_value (null, Database.make_string_value (id));
4180+ var id_cond = sql.add_cond (Gda.SqlOperatorType.EQ, id_field, id_param, 0);
4181+ sql.set_where (id_cond);
4182+ var data_model = connection.statement_execute_select (sql.get_statement (), null);
4183+ return data_model.get_value_at (data_model.get_column_index (field), 0);
4184+ } catch (Error e) {
4185+ critical ("Could not query field %s: %s", field, e.message);
4186+ return null;
4187+ }
4188+ }
4189+
4190+ private void set_field (string field, GLib.Value value) {
4191+ try {
4192+ var col_names = new GLib.SList<string> ();
4193+ col_names.append (field);
4194+ var values = new GLib.SList<GLib.Value?> ();
4195+ values.append (value);
4196+ connection.update_row_in_table_v (Database.Devices.TABLE_NAME, "unique_id", Database.make_string_value (id), col_names, values);
4197+ } catch (Error e) {
4198+ critical ("Could not set field %s: %s", field, e.message);
4199+ }
4200+ }
4201 }
4202
4203=== modified file 'src/LocalBackend/LocalLibrary.vala'
4204--- src/LocalBackend/LocalLibrary.vala 2015-06-12 13:31:55 +0000
4205+++ src/LocalBackend/LocalLibrary.vala 2015-08-27 10:21:27 +0000
4206@@ -36,16 +36,13 @@
4207 * the visual representation of this class
4208 */
4209 public class Noise.LocalLibrary : Library {
4210- public DataBaseUpdater dbu;
4211-
4212 private FileOperator fo;
4213 private GStreamerTagger tagger;
4214
4215 private Gee.TreeSet<StaticPlaylist> _playlists;
4216 private Gee.TreeSet<SmartPlaylist> _smart_playlists;
4217- private Gee.TreeSet<Media> _medias;
4218+ private Gee.HashMap<int64?, Media> _medias;
4219 private Gee.TreeSet<Media> _searched_medias;
4220- private int playlists_rowid = 0;
4221
4222 public StaticPlaylist p_music;
4223
4224@@ -54,64 +51,109 @@
4225 }
4226
4227 private Gee.TreeSet<Media> open_media_list;
4228-
4229 private bool _doing_file_operations = false;
4230
4231+ public Gda.Connection connection { public get; private set; }
4232+ private Gda.SqlParser parser;
4233+
4234+ private static const string DB_FILE = "database_0_3_1";
4235+
4236 public LocalLibrary () {
4237 libraries_manager.local_library = this;
4238 _playlists = new Gee.TreeSet<StaticPlaylist> ();
4239 _smart_playlists = new Gee.TreeSet<SmartPlaylist> ();
4240- _medias = new Gee.TreeSet<Media> ();
4241+ _medias = new Gee.HashMap<int64?, Media> ((Gee.HashDataFunc<int64?>)GLib.int64_hash,
4242+ (Gee.EqualDataFunc<int64?>?)GLib.int64_equal, null);
4243 _searched_medias = new Gee.TreeSet<Media> ();
4244 tagger = new GStreamerTagger();
4245 open_media_list = new Gee.TreeSet<Media> ();
4246 p_music = new StaticPlaylist ();
4247 p_music.name = MUSIC_PLAYLIST;
4248
4249- this.dbu = new DataBaseUpdater ();
4250 this.fo = new FileOperator ();
4251 }
4252
4253 public override void initialize_library () {
4254- var dbm = DataBaseManager.get_default ();
4255+ init_database ();
4256 fo.connect_to_manager ();
4257+
4258 // Load all media from database
4259- lock (_medias) {
4260- foreach (var m in dbm.load_media ()) {
4261- _medias.add (m);
4262- }
4263+ var media_ids = get_rowids_from_table (Database.Media.TABLE_NAME);
4264+ foreach (var media_id in media_ids) {
4265+ var m = new LocalMedia (media_id, connection);
4266+ _medias.set (m.rowid, m);
4267 }
4268
4269- // Load smart playlists from database
4270- lock (_smart_playlists) {
4271- foreach (var p in dbm.load_smart_playlists ()) {
4272- _smart_playlists.add (p);
4273- p.rowid = playlists_rowid;
4274- playlists_rowid++;
4275- p.updated.connect ((old_name) => {smart_playlist_updated (p, old_name);});
4276- }
4277+ // Load all smart playlists from database
4278+ var sp_ids = get_rowids_from_table (Database.SmartPlaylists.TABLE_NAME);
4279+ foreach (var sp_id in sp_ids) {
4280+ var sp = new LocalSmartPlaylist (sp_id, connection);
4281+ _smart_playlists.add (sp);
4282 }
4283
4284 // Load all static playlists from database
4285-
4286- lock (_playlists) {
4287- foreach (var p in dbm.load_playlists ()) {
4288- if (p.name == C_("Name of the playlist", "Queue") || p.name == _("History")) {
4289- continue;
4290- } else if (p.name != MUSIC_PLAYLIST) {
4291- _playlists.add (p);
4292- p.rowid = playlists_rowid;
4293- playlists_rowid++;
4294- p.updated.connect ((old_name) => {playlist_updated (p, old_name);});
4295- continue;
4296- }
4297- }
4298+ var p_ids = get_rowids_from_table (Database.Playlists.TABLE_NAME);
4299+ foreach (var p_id in p_ids) {
4300+ var p = new LocalStaticPlaylist (p_id, connection);
4301+ _playlists.add (p);
4302 }
4303
4304- DeviceManager.get_default ().set_device_preferences (dbm.load_devices ());
4305 load_media_art_cache.begin ();
4306 }
4307
4308+ /*
4309+ * Database interaction
4310+ */
4311+ private void init_database () {
4312+ var database_dir = FileUtils.get_data_directory ();
4313+ try {
4314+ database_dir.make_directory_with_parents (null);
4315+ } catch (GLib.Error err) {
4316+ if (err is IOError.EXISTS == false)
4317+ error ("Could not create data directory: %s", err.message);
4318+ }
4319+
4320+ var db_file = database_dir.get_child (DB_FILE + ".db");
4321+ bool new_db = !db_file.query_exists ();
4322+ if (new_db) {
4323+ try {
4324+ db_file.create (FileCreateFlags.PRIVATE);
4325+ } catch (Error e) {
4326+ critical ("Error: %s", e.message);
4327+ }
4328+ }
4329+
4330+ try {
4331+ connection = new Gda.Connection.from_string ("SQLite", "DB_DIR=%s;DB_NAME=%s".printf (database_dir.get_path (), DB_FILE), null, Gda.ConnectionOptions.NONE);
4332+ connection.open ();
4333+ } catch (Error e) {
4334+ error (e.message);
4335+ }
4336+
4337+ parser = connection.create_parser ();
4338+
4339+ if (new_db) {
4340+ load_table (Database.Tables.PLAYLISTS);
4341+ load_table (Database.Tables.SMART_PLAYLISTS);
4342+ load_table (Database.Tables.COLUMNS);
4343+ load_table (Database.Tables.MEDIA);
4344+ load_table (Database.Tables.DEVICES);
4345+ LocalSmartPlaylist.add_defaults (connection);
4346+ }
4347+ }
4348+
4349+ private void load_table (string table) {
4350+ try {
4351+ var statement = parser.parse_string (table, null);
4352+ connection.statement_execute_non_select (statement, null, null);
4353+ } catch (Error e) {
4354+ critical (e.message);
4355+ }
4356+ }
4357+
4358+ /*
4359+ * Media art utilities.
4360+ */
4361 private async void load_media_art_cache () {
4362 lock (_medias) {
4363 yield CoverartCache.instance.load_for_media_async (get_medias ());
4364@@ -135,7 +177,7 @@
4365 }
4366
4367 public void remove_all_static_playlists () {
4368- var list = new Gee.TreeSet<int> ();
4369+ var list = new Gee.TreeSet<int64?> ();
4370 lock (_playlists) {
4371 foreach (var p in _playlists) {
4372 if (p.read_only == false)
4373@@ -158,9 +200,8 @@
4374
4375 clear_medias ();
4376
4377- App.player.unqueue_media (_medias);
4378+ App.player.unqueue_media (_medias.values);
4379
4380- App.player.reset_already_played ();
4381 // FIXME: these are library window's internals. Shouldn't be here
4382 App.main_window.update_sensitivities.begin ();
4383 App.player.stop_playback ();
4384@@ -339,7 +380,7 @@
4385 return result;
4386 }
4387
4388- public override StaticPlaylist? playlist_from_id (int id) {
4389+ public override StaticPlaylist? playlist_from_id (int64 id) {
4390 lock (_playlists) {
4391 foreach (var p in get_playlists ()) {
4392 if (p.rowid == id) {
4393@@ -367,34 +408,54 @@
4394 }
4395
4396 public override void add_playlist (StaticPlaylist p) {
4397- lock (_playlists) {
4398- _playlists.add (p);
4399- }
4400- p.rowid = playlists_rowid;
4401- playlists_rowid++;
4402- p.updated.connect ((old_name) => {playlist_updated (p, old_name);});
4403- DataBaseManager.get_default ().add_playlist (p);
4404- playlist_added (p);
4405- debug ("playlist %s added",p.name);
4406+ string rv = "";
4407+ foreach (var m in p.medias) {
4408+ if (rv == "") {
4409+ rv = "%lld".printf (m.rowid);
4410+ } else {
4411+ rv += ";%lld".printf (m.rowid);
4412+ }
4413+ }
4414+
4415+ try {
4416+ var builder = new Gda.SqlBuilder (Gda.SqlStatementType.INSERT);
4417+ builder.set_table (Database.Playlists.TABLE_NAME);
4418+ builder.add_field_value_as_gvalue ("name", Database.make_string_value (p.name));
4419+ builder.add_field_value_as_gvalue ("media", Database.make_string_value (rv));
4420+ var statement = builder.get_statement ();
4421+ Gda.Set last_insert_row;
4422+ connection.statement_execute_non_select (statement, null, out last_insert_row);
4423+ var local_p = new LocalStaticPlaylist (last_insert_row.get_holder_value (Database.Playlists.ROWID).get_int64 (), connection);
4424+
4425+ lock (_playlists) {
4426+ _playlists.add (local_p);
4427+ }
4428+
4429+ playlist_added (local_p);
4430+ debug ("playlist %s added", local_p.name);
4431+ } catch (Error e) {
4432+ critical (e.message);
4433+ }
4434 }
4435
4436- public override void remove_playlist (int id) {
4437+ public override void remove_playlist (int64 id) {
4438 lock (_playlists) {
4439 foreach (var playlist in get_playlists ()) {
4440 if (playlist.rowid == id) {
4441 _playlists.remove (playlist);
4442- dbu.removeItem.begin (playlist);
4443 playlist_removed (playlist);
4444 break;
4445 }
4446 }
4447+
4448+ try {
4449+ connection.delete_row_from_table (Database.Playlists.TABLE_NAME, "rowid", Database.make_int64_value (id));
4450+ } catch (Error e) {
4451+ critical (e.message);
4452+ }
4453 }
4454 }
4455
4456- public void playlist_updated (StaticPlaylist p, string? old_name = null) {
4457- dbu.save_playlist (p, old_name);
4458- }
4459-
4460 /*
4461 * Smart playlists
4462 */
4463@@ -409,7 +470,7 @@
4464 return result;
4465 }
4466
4467- public override SmartPlaylist? smart_playlist_from_id (int id) {
4468+ public override SmartPlaylist? smart_playlist_from_id (int64 id) {
4469 lock (_smart_playlists) {
4470 foreach (var p in get_smart_playlists ()) {
4471 if (p.rowid == id) {
4472@@ -433,69 +494,133 @@
4473 return null;
4474 }
4475
4476- public async void save_smart_playlists () {
4477- lock (_smart_playlists) {
4478- DataBaseManager.get_default ().save_smart_playlists (get_smart_playlists ());
4479- }
4480- }
4481-
4482 public override void add_smart_playlist (SmartPlaylist p) {
4483- lock (_smart_playlists) {
4484- _smart_playlists.add (p);
4485+ try {
4486+ var builder = new Gda.SqlBuilder (Gda.SqlStatementType.INSERT);
4487+ builder.set_table (Database.SmartPlaylists.TABLE_NAME);
4488+ builder.add_field_value_as_gvalue ("name", Database.make_string_value (p.name));
4489+ var statement = builder.get_statement ();
4490+ Gda.Set last_insert_row;
4491+ connection.statement_execute_non_select (statement, null, out last_insert_row);
4492+ if (last_insert_row != null) {
4493+ var local_sp = new LocalSmartPlaylist (last_insert_row.get_holder_value (Database.SmartPlaylists.ROWID).get_int64 (), connection);
4494+ local_sp.conditional = p.conditional;
4495+ local_sp.limit = p.limit;
4496+ local_sp.limit_amount = p.limit_amount;
4497+ local_sp.add_queries (p.get_queries ());
4498+
4499+ lock (_smart_playlists) {
4500+ _smart_playlists.add (local_sp);
4501+ }
4502+
4503+ smartplaylist_added (local_sp);
4504+ }
4505+ } catch (Error e) {
4506+ critical (e.message);
4507 }
4508-
4509- p.rowid = playlists_rowid;
4510- playlists_rowid++;
4511- DataBaseManager.get_default ().save_smart_playlist (p);
4512- p.updated.connect ((old_name) => {smart_playlist_updated (p, old_name);});
4513- smartplaylist_added (p);
4514 }
4515
4516- public override void remove_smart_playlist (int id) {
4517+ public override void remove_smart_playlist (int64 id) {
4518 lock (_smart_playlists) {
4519 foreach (var p in get_smart_playlists ()) {
4520 if (p.rowid == id) {
4521 _smart_playlists.remove (p);
4522 smartplaylist_removed (p);
4523- dbu.removeItem.begin (p);
4524 break;
4525 }
4526 }
4527 }
4528- }
4529-
4530- public void smart_playlist_updated (SmartPlaylist p, string? old_name = null) {
4531- dbu.save_smart_playlist (p, old_name);
4532- }
4533+
4534+ try {
4535+ connection.delete_row_from_table (Database.SmartPlaylists.TABLE_NAME, "rowid", Database.make_int64_value (id));
4536+ } catch (Error e) {
4537+ critical (e.message);
4538+ }
4539+ }
4540+
4541
4542 /******************** Media stuff ******************/
4543
4544 public override void search_medias (string search) {
4545- lock (_searched_medias) {
4546- _searched_medias.clear ();
4547- if (search == "") {
4548- _searched_medias.add_all (_medias);
4549- search_finished ();
4550- return;
4551- }
4552-
4553- int parsed_rating;
4554- string parsed_search_string;
4555- String.base_search_method (search, out parsed_rating, out parsed_search_string);
4556- bool rating_search = parsed_rating > 0;
4557- lock (_medias) {
4558- foreach (var m in _medias) {
4559- if (rating_search) {
4560- if (m.rating == (uint) parsed_rating)
4561- _searched_medias.add (m);
4562- } else if (Search.match_string_to_media (m, parsed_search_string)) {
4563- _searched_medias.add (m);
4564- }
4565- }
4566- }
4567- }
4568-
4569- search_finished ();
4570+ if (search == "") {
4571+ lock (_searched_medias) {
4572+ _searched_medias.clear ();
4573+ _searched_medias.add_all (_medias.values);
4574+ }
4575+ search_finished ();
4576+ return;
4577+ }
4578+
4579+ uint parsed_rating;
4580+ string parsed_search_string;
4581+ String.base_search_method (search, out parsed_rating, out parsed_search_string);
4582+ bool rating_search = parsed_rating > 0;
4583+ // If we search for a special rating, don't search for something else.
4584+ try {
4585+ if (parsed_rating > 0) {
4586+ var sql = new Gda.SqlBuilder (Gda.SqlStatementType.SELECT);
4587+ sql.select_add_target (Database.Media.TABLE_NAME, null);
4588+ sql.select_add_field ("rowid", null, null);
4589+ var id_field = sql.add_id ("rating");
4590+ var id_value = sql.add_expr_value (null, Database.make_uint_value (parsed_rating));
4591+ var id_cond = sql.add_cond (Gda.SqlOperatorType.GEQ, id_field, id_value, 0);
4592+ sql.set_where (id_cond);
4593+
4594+ var statm = sql.get_statement ();
4595+ var data_model = connection.statement_execute_select (statm, null);
4596+ var data_model_iter = data_model.create_iter ();
4597+ data_model_iter.move_to_row (-1);
4598+ var rowids = new Gee.TreeSet<int64?> ();
4599+ while (data_model_iter.move_next ()) {
4600+ unowned Value? val = data_model_iter.get_value_at (0);
4601+ rowids.add (val.get_int64 ());
4602+ }
4603+
4604+ var meds = medias_from_ids (rowids);
4605+ lock (_searched_medias) {
4606+ _searched_medias.clear ();
4607+ _searched_medias.add_all (meds);
4608+ }
4609+ } else {
4610+ var sql = new Gda.SqlBuilder (Gda.SqlStatementType.SELECT);
4611+ sql.select_add_target (Database.Media.TABLE_NAME, null);
4612+ sql.select_add_field ("rowid", null, null);
4613+ Gda.SqlBuilderId[] ids = null;
4614+
4615+ string[] fields = {"title", "artist", "composer", "album_artist", "album", "grouping", "comment"};
4616+ foreach (var field in fields) {
4617+ var id_field = sql.add_id (field);
4618+ var id_value = sql.add_expr_value (null, Database.make_string_value ("%"+search+"%"));
4619+ ids += sql.add_cond (Gda.SqlOperatorType.LIKE, id_field, id_value, 0);
4620+ }
4621+
4622+ var id_cond = sql.add_cond_v (Gda.SqlOperatorType.OR, ids);
4623+ sql.set_where (id_cond);
4624+
4625+ var statm = sql.get_statement ();
4626+ var data_model = connection.statement_execute_select (statm, null);
4627+ var data_model_iter = data_model.create_iter ();
4628+ data_model_iter.move_to_row (-1);
4629+ var rowids = new Gee.TreeSet<int64?> ();
4630+ while (data_model_iter.move_next ()) {
4631+ unowned Value? val = data_model_iter.get_value_at (0);
4632+ rowids.add (val.get_int64 ());
4633+ }
4634+
4635+ var meds = medias_from_ids (rowids);
4636+ lock (_searched_medias) {
4637+ _searched_medias.clear ();
4638+ _searched_medias.add_all (meds);
4639+ }
4640+ }
4641+ } catch (Error e) {
4642+ critical ("Could not search for %s: %s", search, e.message);
4643+ }
4644+
4645+ Idle.add (() => {
4646+ search_finished ();
4647+ return GLib.Source.REMOVE;
4648+ });
4649 }
4650
4651 public override Gee.Collection<Media> get_search_result () {
4652@@ -510,7 +635,7 @@
4653 // We really only want to clear the songs that are permanent and on the file system
4654 // Dont clear podcasts that link to a url, device media, temporary media, previews, songs
4655 var unset = new Gee.LinkedList<Media> ();
4656- foreach (var s in _medias) {
4657+ foreach (var s in _medias.values) {
4658 if (!s.isTemporary && !s.isPreview)
4659 unset.add (s);
4660 }
4661@@ -521,7 +646,7 @@
4662
4663 public override Gee.Collection<Media> get_medias () {
4664 var result = new Gee.TreeSet<Media> ();
4665- result.add_all (_medias);
4666+ result.add_all (_medias.values);
4667 return result;
4668 }
4669
4670@@ -553,21 +678,14 @@
4671 * consistency
4672 */
4673
4674- public override Media? media_from_id (int id) {
4675- lock (_medias) {
4676- foreach (var m in _medias) {
4677- if (m.rowid == id)
4678- return m;
4679- }
4680- }
4681-
4682- return null;
4683+ public override Media? media_from_id (int64 id) {
4684+ return _medias.get (id);
4685 }
4686
4687 public override Media? find_media (Media to_find) {
4688 Media? found = null;
4689 lock (_medias) {
4690- foreach (var m in _medias) {
4691+ foreach (var m in _medias.values) {
4692 if (to_find.title.down () == m.title.down () && to_find.artist.down () == m.artist.down ()) {
4693 found = m;
4694 break;
4695@@ -580,7 +698,7 @@
4696
4697 public override Media? media_from_file (File file) {
4698 lock (_medias) {
4699- foreach (var m in _medias) {
4700+ foreach (var m in _medias.values) {
4701 if (m != null && m.file.equal (file))
4702 return m;
4703 }
4704@@ -591,7 +709,7 @@
4705
4706 public override Media? media_from_uri (string uri) {
4707 lock (_medias) {
4708- foreach (var m in _medias) {
4709+ foreach (var m in _medias.values) {
4710 if (m != null && m.uri == uri)
4711 return m;
4712 }
4713@@ -600,15 +718,12 @@
4714 return null;
4715 }
4716
4717- public override Gee.Collection<Media> medias_from_ids (Gee.Collection<int> ids) {
4718+ public override Gee.Collection<Media> medias_from_ids (Gee.Collection<int64?> ids) {
4719 var media_collection = new Gee.TreeSet<Media> ();
4720- lock (_medias) {
4721- foreach (var m in _medias) {
4722- if (ids.contains (m.rowid))
4723- media_collection.add (m);
4724-
4725- if (media_collection.size == ids.size)
4726- break;
4727+ foreach (var id in ids) {
4728+ var m = _medias.get (id);
4729+ if (m != null) {
4730+ media_collection.add (m);
4731 }
4732 }
4733
4734@@ -618,7 +733,7 @@
4735 public override Gee.Collection<Media> medias_from_uris (Gee.Collection<string> uris) {
4736 var media_collection = new Gee.LinkedList<Media> ();
4737 lock (_medias) {
4738- foreach (var m in _medias) {
4739+ foreach (var m in _medias.values) {
4740 if (uris.contains (m.uri))
4741 media_collection.add (m);
4742 if (media_collection.size == uris.size)
4743@@ -636,7 +751,7 @@
4744 }
4745
4746 public override void add_medias (Gee.Collection<Media> new_media) {
4747- if (new_media.size < 1) // happens more often than you would think
4748+ if (new_media.is_empty) // happens more often than you would think
4749 return;
4750
4751 // make a copy of the media list so that it doesn't get modified before
4752@@ -644,21 +759,26 @@
4753 var media = new Gee.TreeSet<Media> ();
4754 media.add_all (new_media);
4755
4756- var local_media = DataBaseManager.get_default ().add_media (media);
4757- _medias.add_all (local_media);
4758- media_added (local_media.read_only_view);
4759+ var local_media = new Gee.HashMap<int64?, LocalMedia> ();
4760+ foreach (var m in media) {
4761+ var local_m = new LocalMedia.from_media (connection, m);
4762+ local_media.set (local_m.rowid, local_m);
4763+ }
4764+
4765+ _medias.set_all (local_media);
4766+ media_added (local_media.values.read_only_view);
4767
4768 // Update search results
4769 if (App.main_window.searchField.text == "") {
4770- _searched_medias.add_all (local_media);
4771+ _searched_medias.add_all (local_media.values);
4772 } else {
4773- int parsed_rating;
4774+ uint parsed_rating;
4775 string parsed_search_string;
4776 String.base_search_method (App.main_window.searchField.text, out parsed_rating, out parsed_search_string);
4777 bool rating_search = parsed_rating > 0;
4778- foreach (var m in local_media) {
4779+ foreach (var m in local_media.values) {
4780 if (rating_search) {
4781- if (m.rating == (uint) parsed_rating)
4782+ if (m.rating == parsed_rating)
4783 _searched_medias.add (m);
4784 } else if (Search.match_string_to_media (m, parsed_search_string)) {
4785 _searched_medias.add (m);
4786@@ -678,10 +798,8 @@
4787 public override void remove_medias (Gee.Collection<Media> to_remove, bool trash) {
4788 var toRemove = new Gee.TreeSet<Media> ();
4789 toRemove.add_all (to_remove);
4790- foreach (var s in toRemove) {
4791- if (s == App.player.current_media)
4792- App.player.stop_playback ();
4793- }
4794+ if (App.player.current_media in toRemove)
4795+ App.player.stop_playback ();
4796
4797 if (trash)
4798 fo.remove_media (toRemove);
4799@@ -689,12 +807,11 @@
4800 // Emit signal before actually removing the media because otherwise
4801 // media_from_id () and media_from_ids () wouldn't work.
4802 media_removed (toRemove.read_only_view);
4803- dbu.removeItem.begin (toRemove);
4804
4805 lock (_medias) {
4806 foreach (Media s in toRemove) {
4807 _searched_medias.remove (s);
4808- _medias.remove (s);
4809+ _medias.unset (s.rowid);
4810 }
4811 }
4812
4813@@ -703,17 +820,25 @@
4814 p.remove_medias (toRemove);
4815 }
4816
4817- DataBaseManager.get_default ().remove_media (toRemove);
4818+ foreach (var m in toRemove) {
4819+ try {
4820+ connection.delete_row_from_table (Database.Media.TABLE_NAME, "rowid", Database.make_int64_value (m.rowid));
4821+ } catch (Error e) {
4822+ critical (e.message);
4823+ }
4824+ }
4825+
4826 search_finished ();
4827 }
4828
4829 public Gee.TreeSet<Noise.Media> answer_to_device_sync (Device device) {
4830 var medias_to_sync = new Gee.TreeSet<Noise.Media> ();
4831- if (device.get_preferences ().sync_music == true) {
4832- if (device.get_preferences ().sync_all_music == true) {
4833+ var prefs = get_preferences_for_device (device);
4834+ if (prefs.sync_music == true) {
4835+ if (prefs.sync_all_music == true) {
4836 medias_to_sync.add_all (get_medias ());
4837 } else {
4838- medias_to_sync.add_all (device.get_preferences ().music_playlist.medias);
4839+ medias_to_sync.add_all (prefs.music_playlist.medias);
4840 }
4841 }
4842
4843@@ -744,4 +869,35 @@
4844 file_operations_done ();
4845 update_media_art_cache.begin ();
4846 }
4847+
4848+ Gee.HashMap<string, DevicePreferences> preferences = new Gee.HashMap<string, DevicePreferences> ((Gee.HashDataFunc)GLib.str_hash, (Gee.EqualDataFunc)GLib.str_equal);
4849+ public DevicePreferences get_preferences_for_device (Device d) {
4850+ var key = d.get_unique_identifier ();
4851+ if (preferences.has_key (key)) {
4852+ return preferences.get (key);
4853+ } else {
4854+ var pref = new DevicePreferences (d, connection);
4855+ preferences.set (key, pref);
4856+ return pref;
4857+ }
4858+ }
4859+
4860+ private Gee.Collection<int64?> get_rowids_from_table (string table_name) {
4861+ var ids = new Gee.TreeSet<int64?> ();
4862+ try {
4863+ var builder = new Gda.SqlBuilder (Gda.SqlStatementType.SELECT);
4864+ builder.select_add_target (table_name, null);
4865+ builder.select_add_field ("rowid", null, null);
4866+ var data_model = connection.statement_execute_select (builder.get_statement (), null);
4867+ for (int i = 0; i < data_model.get_n_rows (); i++) {
4868+ var rowid = data_model.get_value_at (data_model.get_column_index ("rowid"), i);
4869+ ids.add (rowid.get_int64 ());
4870+ }
4871+ } catch (Error e) {
4872+ // TODO: Expose errors to the user !
4873+ critical ("Could not query table %s : %s", table_name, e.message);
4874+ }
4875+
4876+ return ids;
4877+ }
4878 }
4879
4880=== modified file 'src/LocalBackend/LocalMedia.vala'
4881--- src/LocalBackend/LocalMedia.vala 2015-02-24 18:16:35 +0000
4882+++ src/LocalBackend/LocalMedia.vala 2015-08-27 10:21:27 +0000
4883@@ -29,8 +29,6 @@
4884 */
4885
4886 public class Noise.LocalMedia : Noise.Media {
4887- private SQLHeavy.Database database = Noise.DataBaseManager.get_default ().database;
4888-
4889 private uint64? _file_size = null;
4890 public override uint64 file_size {
4891 get {
4892@@ -66,6 +64,7 @@
4893 common_uint_setter ("track", value, ref _track);
4894 }
4895 }
4896+
4897 private uint? _track_count = null;
4898 public override uint track_count {
4899 get {
4900@@ -76,6 +75,7 @@
4901 common_uint_setter ("track_count", value, ref _track_count);
4902 }
4903 }
4904+
4905 private string _composer = null;
4906 public override string composer {
4907 get {
4908@@ -86,6 +86,7 @@
4909 common_string_setter ("composer", value, ref _composer);
4910 }
4911 }
4912+
4913 private string _artist = null;
4914 public override string artist {
4915 get {
4916@@ -96,6 +97,7 @@
4917 common_string_setter ("artist", value, ref _artist);
4918 }
4919 }
4920+
4921 private string _album_artist = null;
4922 public override string album_artist {
4923 get {
4924@@ -106,6 +108,7 @@
4925 common_string_setter ("album_artist", value, ref _album_artist);
4926 }
4927 }
4928+
4929 private string _album = null;
4930 public override string album {
4931 get {
4932@@ -116,6 +119,7 @@
4933 common_string_setter ("album", value, ref _album);
4934 }
4935 }
4936+
4937 private uint? _album_number = null;
4938 public override uint album_number {
4939 get {
4940@@ -126,6 +130,7 @@
4941 common_uint_setter ("album_number", value, ref _album_number);
4942 }
4943 }
4944+
4945 private uint? _album_count = null;
4946 public override uint album_count {
4947 get {
4948@@ -136,6 +141,7 @@
4949 common_uint_setter ("album_count", value, ref _album_count);
4950 }
4951 }
4952+
4953 public override unowned Album album_info { get; set; default = null; }
4954 private string _grouping = null;
4955 public override string grouping {
4956@@ -147,6 +153,7 @@
4957 common_string_setter ("grouping", value, ref _grouping);
4958 }
4959 }
4960+
4961 private string _genre = null;
4962 public override string genre {
4963 get {
4964@@ -157,6 +164,7 @@
4965 common_string_setter ("genre", value, ref _genre);
4966 }
4967 }
4968+
4969 private string _comment = null;
4970 public override string comment {
4971 get {
4972@@ -167,6 +175,7 @@
4973 common_string_setter ("comment", value, ref _comment);
4974 }
4975 }
4976+
4977 private string _lyrics = null;
4978 public override string lyrics {
4979 get {
4980@@ -177,6 +186,7 @@
4981 common_string_setter ("lyrics", value, ref _lyrics);
4982 }
4983 }
4984+
4985 public uint? _year = null;
4986 public override uint year {
4987 get {
4988@@ -187,6 +197,7 @@
4989 common_uint_setter ("year", value, ref _year);
4990 }
4991 }
4992+
4993 public uint? _bitrate = null;
4994 public override uint bitrate {
4995 get {
4996@@ -197,6 +208,7 @@
4997 common_uint_setter ("bitrate", value, ref _bitrate);
4998 }
4999 }
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches