From 5618c9016c41e34974521c68e817687078559a2a Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 15 Jan 2023 15:18:35 +0100 Subject: [PATCH 01/10] Always return tuple by get_albumart_now() (close #89) --- src/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.py b/src/client.py index b2a5d69..3929d26 100644 --- a/src/client.py +++ b/src/client.py @@ -653,7 +653,7 @@ class Client(Base): if album in self._albums: album = self._albums[album] if not album.get_tracks(): - return None + return (album, None) self._logger.debug("get albumart for album \"%s\"", album.get_title()) size = 1 offset = 0 From 8607bf15a90f5ba0814c97b7e35ef32e4a4632c4 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 8 Jan 2023 19:09:19 +0100 Subject: [PATCH 02/10] Add option to sort by last modification date (close #88) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store the metadate “last-modified” for a track and an album and add an option sort by it. --- data/ui/library-toolbar.ui | 18 +++++++++++++++++- data/xyz.suruatoel.mcg.gschema.xml | 1 + po/de.mo | Bin 4190 -> 4246 bytes po/de.po | 22 +++++++++++++--------- po/en.mo | Bin 3931 -> 4042 bytes po/en.po | 22 +++++++++++++--------- po/mcg.pot | 16 ++++++++++------ src/client.py | 26 ++++++++++++++++++++++++++ src/librarypanel.py | 4 +++- src/utils.py | 1 + 10 files changed, 84 insertions(+), 26 deletions(-) diff --git a/data/ui/library-toolbar.ui b/data/ui/library-toolbar.ui index 97cad01..aabcc8f 100644 --- a/data/ui/library-toolbar.ui +++ b/data/ui/library-toolbar.ui @@ -129,6 +129,22 @@ 4 + + + sort by modification + True + True + False + True + sort_year + + + + False + True + 5 + + gtk-sort-descending @@ -143,7 +159,7 @@ False True - 5 + 6 diff --git a/data/xyz.suruatoel.mcg.gschema.xml b/data/xyz.suruatoel.mcg.gschema.xml index 934564c..9f50878 100644 --- a/data/xyz.suruatoel.mcg.gschema.xml +++ b/data/xyz.suruatoel.mcg.gschema.xml @@ -4,6 +4,7 @@ + diff --git a/po/de.mo b/po/de.mo index da025a58e832a15d8da250d349124781c1c8f3c1..abfee53fda80f21b12bf31bcc5049bc16bef6d96 100644 GIT binary patch delta 1618 zcmYk*OK4MB9LMpKG>tZ~58sZX)2OYEmK&2)r#5!%*oTVvs9Nv^maDnOKy6AM3R2A= zf}+f#Tpa`%unKNObj)TJf()|}1zm_DE>r{;g6Kj=7Yh3Q#VdHY|9tM_JpSi@Z=OW{ zoKt!-DR9QnRuQv^b$(-P90~BF7BnUdKAecP$YB~i=i@l8Ev&_*-u-SI&-GfY!!0-o zccc0jajG#TbJ*+PVu%M9uo|zR7B1re-b5wX$mrSFf!s1XQ2lM>Flp~Pi`qjGweTV2 zFn{o)M9*Ly>zj*}6JxI96dwGGHTV!U!86oCFHk#rg<9}`@A*g6I6c%(r=k{YLLQkm z?|vuNbG-ql;VulazA18|2}W=Zj^dA4MlEy?mB<5Bg&t!iAyg$^;ZGPM>mP6-YJ4}U zVgsmoMo_QtC~Ev^ENS9%UWfDEgG;ELT=BetO7ISos}MK~XqU<2+%Rb&vgz(M3N zhxs{(Cvh(N$woG#UdbBNdVRIjUlVWTh9Rh4)YDWYjdjqAl`T!;E*N;yvS(TsXGE~6&Ajhg5+Dv@`n9R|rpHh9kT zY(i}$isWE=QI+aPC6YmnD|jA3isLsY-0gwRnx#BaK^D7Xfywb0XKE{nB+;!4ns%V1 zx`-8o7En2V(J1#?AmDxqG?e1pSw(znO`Nn5szZd(f1-!52(mEKi7GL zo^Do;U2u|-L@d#2#o|_MStQ<`jJ37I;_lqghN^*{UUxXO)Afa|*456Cld}uiTr$#^ zbyAr^q&1p|CPLe+ua{Prop*-q!oFlA8eLpD+?H@-`B->jRd9<_N%M5w1z-Jt$A(f) Rt~iv=r|d#;zZ+|aegRHHtegM< delta 1560 zcmYk+TSyd99LMpa?w0PRnU}KKYP7qx>#nX{R?{@AhoClM!Lo=!mu{$GDPnX{`Yfc&YW}p=Rbo3myu@Vcg28*y6^?U+L zjY*pW?gJ;#$G}-+ZF2>+v4aP35S8E*F2Vq-&^0mC^G&FQx4YN7P-jS>Hr|K)nNEI` zXfGD9zd1MEG3F|kFffF9cn`I}W7I|?s1rRyZTQ9=|A3k|jymag)P^1&rfcS*?k~aF z7{a;OfF!vWR2m0KBG%C}JuKlP|UBg*;7xhXWx%bELW|lGU-0KSrmND+2)*VKM%w5+9 zsC7nBiM;Ytf08%vxuMcb-~#-HnpnWoE3ga;u@O~?IBJ77groWw4yz|XFEWUp7S z7PVm%wQe11{?>fzuTt#bMlr@w8+4#b){T0%XOOSe44~fKFlwQvuFp~L{4MGrUr`(U zL?xiIYJM(i{$kWYYtwX8fjDZzy{MBOLzVIr>cM_oinlS0uTdL#*-Z)ik)oNosFPOU za$Jr2Ms}gTkuLZ85^6pBIvp)EhDzWi>SPnHldeBpv&c>-@FO{x3RD6S)VzAvZOGwG z-0AZ)=0)l0{2}Lwr#MnYPi-@?k!T{+l(=$H+eE1Hs$Q*TIWIgOC*Unihq=>2{AtVR ztRr-Mi_oXvOsJ8BnMdRhI&LGOtW)Yv!`r2w+gWHo`$sRk^-4nCo-N}w4DXTgZ4Mlvd!QYp`X8T0)xScv2vqGV&=|9Kv zhn(~Nz{bDN>`B@^?T6z$6%5C$&h|t9rvEn-iCG\n" "Language-Team: \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.4.1\n" -"X-Poedit-Basepath: ../../..\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.2.2\n" +"X-Poedit-Basepath: ../../..\n" "X-Poedit-SourceCharset: UTF-8\n" #: data/xyz.suruatoel.mcg.gschema.xml:11 @@ -216,15 +216,19 @@ msgstr "nach Titel" msgid "sort by year" msgstr "nach Jahr" -#: data/ui/library-toolbar.ui:169 data/ui/shortcuts-dialog.ui:115 +#: data/ui/library-toolbar.ui:134 +msgid "sort by modification" +msgstr "nach Änderungsdatum" + +#: data/ui/library-toolbar.ui:185 data/ui/shortcuts-dialog.ui:115 msgid "Search the library" msgstr "Die Bibliothek durchsuchen" -#: data/ui/library-toolbar.ui:192 data/ui/playlist-toolbar.ui:15 +#: data/ui/library-toolbar.ui:208 data/ui/playlist-toolbar.ui:15 msgid "Select multiple albums" msgstr "Mehrere Alben auswählen" -#: data/ui/library-toolbar.ui:214 +#: data/ui/library-toolbar.ui:230 msgid "Settings and actions" msgstr "Einstellungen und Aktionen" @@ -353,11 +357,11 @@ msgstr "Zu MPD verbinden" msgid "Adjust the volume" msgstr "Die Lautstärke anpassen" -#: src/librarypanel.py:419 +#: src/librarypanel.py:421 msgid "Loading albums" msgstr "Alben werden geladen" -#: src/librarypanel.py:519 +#: src/librarypanel.py:521 msgid "Loading images" msgstr "Bilder werden geladen" diff --git a/po/en.mo b/po/en.mo index 39a611bfc9450b522475a80bd696a35fed4a99bd..8fa584c622e4f01f211e77efe784de52feb62f08 100644 GIT binary patch delta 1610 zcmYk+S!_&E9LMo9HKm;{+S=D%`%-s03(6>^txCie`cO+WL$4a!FrA7>WyGUIM6N!F z#7>Bi#&{tT@#295FO`N^UU(9`NF+S?{_05F-2Z&;J?EbDKj(jM=I!KX)w%ao!Cu4B zLQEvq6d04lo*+Luh8j}>0j$I_hUmD0g?I;*IFIf47`4D^Mo+?eq{(bSJ)cBQ(`oP1s6BL}5+6lQbBZ4=v=__C zZ>|nr7;_It((wd~@il6KkEleSP&@j9O8CR}|3ZyZr*=9Dm2f)JW$J8u0}khY9gfEB zIF$URn+r|QgH!MfPQW}W(M!}q`cV~ngM$k~RpJXy#t^F>hjUQln@|;NN6piNdW9!Y zI}eS})zb5!X*Vkv$_y`o>XeHg2|7N7#C_J{l^;Zsz?0qX}; zWj>cse@*z+cKk**V}>xh7Ep>ReUsv=uaJKTj#VfLZEnIotQ44^9Y z1GSJ5B-Qid%c#F5c5K6JR7Jw5#Bo%A3v!xu{Agj@tb0+FIf@j)oJNg5he~t-wV~^% zgm-QKebl%IIW9Ee3sk~)sD$6GKT#iz9@0lsftq+0YJxE8n`y#1=%EswMpdTQdI>e| zHmVZ$P~S}M6&LzwzFCXOrjkuVO|%^K4qH$Yw4rv`Zu>iI`yONpa|l(5|~ zLH~EKA{V8lh4^<&=c0~KT8Gf~nhBSvAjS|wh-t)ff@KXZS@qM=K+GU&h_M78k(o~{ zA#`ZFa|!-AO-zea9Txd#3ae+txmrvtCF+S;#7g4-Bb@IqJW&wL9QHE#)}ppR>Hc&_ zYFBD!GMh>t@UIqcso&@wOlPw0+OE!2huhfQ+2yvT6HaKudUvCDIMu~tZgVp0C7f6! z7I!02H?qiyE>1-1Y9dj8YUq|9C~@PfyaQe)nN4RB&W5ztk;*#pa4Z}PwYh(9-Ns~> pcQBdVop8e8+QBnlQ*!(7!u-~vP5GJSWr51I|1Hi@R=;-mygztjsOi}hTmVH)P5=1ciW#tKZw8qC60)cxI< zYfQ}a*&Bw@!^AkUwwXdDcJMG>MHRS;MOerxbWH?xe+z2i4tu>HwTEt0;)BSa8Q@2S zj$%6b&H1&CF_$ohiEEgG_fZSXqY^EkcJvCBaM8{$p`Ket?eqsKp^Ka8nmp8a31(mb zH)0d!kl%FE*^DP~6HcNM%%Tdog*urys*p#h6Ij4vT)_fNq-s51h&rh{)H>a$SJ#Vr zegL)Z2*z~7n4O5BD!pKxMjh34OvQVsSMu17zr?8oW8T~GV@xX1Fe=f6brN+F4r;y2 zc6`pu`BS{P!+;V$KpovP)B{V%M`Bj&{7=+LBvXwF&qjt!0qPqmL+yM5bwV?!LgrET zKSizk+FmcFa{fAsB?gpu+1~ISRp~EOVJTe5eAK%xM>cI5QO~!d675B8=m08Vubq#g zo;!+K=PWAU#TXq`bj5lD^^x2}eIyT2557ZvBVTYkdRavYYEdWBU~NYg(uF#K9@IB- z2K9|hTW_OID*Bv`7W#yGcVAHp{6_7}O*NYLpvE(iDU*jffvu<=2T>cTN4=63q*k-f z8FMwKgz4!;2An6Z>`)awwcSKL(L$(cedSWyMQGz%vsOS|*W4tRqT^WeLQT7@Ao#~\n" "Language-Team: \n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.4.1\n" -"X-Poedit-Basepath: ../../..\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.2.2\n" +"X-Poedit-Basepath: ../../..\n" "X-Poedit-SearchPath-0: mcg\n" "X-Poedit-SearchPath-1: data/ui\n" @@ -217,15 +217,19 @@ msgstr "by Title" msgid "sort by year" msgstr "by Year" -#: data/ui/library-toolbar.ui:169 data/ui/shortcuts-dialog.ui:115 +#: data/ui/library-toolbar.ui:134 +msgid "sort by modification" +msgstr "by Modification Date" + +#: data/ui/library-toolbar.ui:185 data/ui/shortcuts-dialog.ui:115 msgid "Search the library" msgstr "Search the library" -#: data/ui/library-toolbar.ui:192 data/ui/playlist-toolbar.ui:15 +#: data/ui/library-toolbar.ui:208 data/ui/playlist-toolbar.ui:15 msgid "Select multiple albums" msgstr "Select multiple albums" -#: data/ui/library-toolbar.ui:214 +#: data/ui/library-toolbar.ui:230 msgid "Settings and actions" msgstr "Settings and actions" @@ -354,11 +358,11 @@ msgstr "Connect to MPD" msgid "Adjust the volume" msgstr "Adjust the volume" -#: src/librarypanel.py:419 +#: src/librarypanel.py:421 msgid "Loading albums" msgstr "Loading albums" -#: src/librarypanel.py:519 +#: src/librarypanel.py:521 msgid "Loading images" msgstr "Loading images" diff --git a/po/mcg.pot b/po/mcg.pot index 19fd383..c409fd6 100644 --- a/po/mcg.pot +++ b/po/mcg.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: mcg\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-05 15:08+0200\n" +"POT-Creation-Date: 2023-01-08 19:06+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -215,15 +215,19 @@ msgstr "" msgid "sort by year" msgstr "" -#: data/ui/library-toolbar.ui:169 data/ui/shortcuts-dialog.ui:115 +#: data/ui/library-toolbar.ui:134 +msgid "sort by modification" +msgstr "" + +#: data/ui/library-toolbar.ui:185 data/ui/shortcuts-dialog.ui:115 msgid "Search the library" msgstr "" -#: data/ui/library-toolbar.ui:192 data/ui/playlist-toolbar.ui:15 +#: data/ui/library-toolbar.ui:208 data/ui/playlist-toolbar.ui:15 msgid "Select multiple albums" msgstr "" -#: data/ui/library-toolbar.ui:214 +#: data/ui/library-toolbar.ui:230 msgid "Settings and actions" msgstr "" @@ -352,11 +356,11 @@ msgstr "" msgid "Adjust the volume" msgstr "" -#: src/librarypanel.py:419 +#: src/librarypanel.py:421 msgid "Loading albums" msgstr "" -#: src/librarypanel.py:519 +#: src/librarypanel.py:521 msgid "Loading images" msgstr "" diff --git a/src/client.py b/src/client.py index 3929d26..cc043d8 100644 --- a/src/client.py +++ b/src/client.py @@ -3,6 +3,7 @@ import concurrent.futures import configparser +import dateutil.parser import logging import os import queue @@ -937,6 +938,8 @@ class Client(Base): track.set_date(song['date']) if 'albumartist' in song: track.set_albumartists(song['albumartist']) + if 'last-modified' in song: + track.set_last_modified(song['last-modified']) return track @@ -998,6 +1001,7 @@ class MCGAlbum: self._host = host self._tracks = [] self._length = 0 + self._last_modified = None self._id = Utils.generate_id(title) @@ -1057,6 +1061,9 @@ class MCGAlbum: path = os.path.dirname(track.get_file()) if path not in self._pathes: self._pathes.append(path) + if track.get_last_modified(): + if not self._last_modified or track.get_last_modified() > self._last_modified: + self._last_modified = track.get_last_modified() def get_tracks(self): @@ -1067,6 +1074,10 @@ class MCGAlbum: return self._length + def get_last_modified(self): + return self._last_modified + + def filter(self, filter_string): if len(filter_string) == 0: return True @@ -1102,6 +1113,8 @@ class MCGAlbum: value_function = "get_title" elif criterion == SortOrder.YEAR: value_function = "get_date" + elif criterion == SortOrder.MODIFIED: + value_function = "get_last_modified" value1 = getattr(album1, value_function)() value2 = getattr(album2, value_function)() @@ -1137,6 +1150,7 @@ class MCGTrack: self._track = None self._length = 0 self._date = None + self._last_modified = None def __eq__(self, other): @@ -1208,6 +1222,18 @@ class MCGTrack: return self._file + def set_last_modified(self, date_string): + if date_string: + try: + self._last_modified = dateutil.parser.isoparse(date_string) + except ValueError as e: + self._logger.debug("Invalid date format: %s", date_string) + + + def get_last_modified(self): + return self._last_modified + + class MCGPlaylistTrack(MCGTrack): diff --git a/src/librarypanel.py b/src/librarypanel.py index 48b5342..2626c7b 100644 --- a/src/librarypanel.py +++ b/src/librarypanel.py @@ -39,6 +39,7 @@ class LibraryToolbar(Gtk.ButtonBox): sort_artist = Gtk.Template.Child() sort_title = Gtk.Template.Child() sort_year = Gtk.Template.Child() + sort_modified = Gtk.Template.Child() grid_scale = Gtk.Template.Child() @@ -50,7 +51,8 @@ class LibraryToolbar(Gtk.ButtonBox): self._toolbar_sort_buttons = { SortOrder.ARTIST: self.sort_artist, SortOrder.TITLE: self.sort_title, - SortOrder.YEAR: self.sort_year + SortOrder.YEAR: self.sort_year, + SortOrder.MODIFIED: self.sort_modified } diff --git a/src/utils.py b/src/utils.py index 713c85c..e5a08bd 100644 --- a/src/utils.py +++ b/src/utils.py @@ -86,3 +86,4 @@ class SortOrder: ARTIST = 0 TITLE = 1 YEAR = 2 + MODIFIED = 3 From a1e87e89945f6f3ad6aa08430096067e36ef5b49 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 8 Jan 2023 19:12:40 +0100 Subject: [PATCH 03/10] =?UTF-8?q?Add=20new=20dependency=20=E2=80=9Cpython-?= =?UTF-8?q?dateutil=E2=80=9D=20to=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 070cd52..083b151 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ License: [GPL](http://www.gnu.org/licenses/gpl.html) v3 Dependencies: * [Python](http://www.python.org) 3 +* [python-dateutil](https://pypi.org/project/python-dateutil/) * [GTK](http://www.gtk.org) 3 (>= 3.22) ([python-gobject](https://live.gnome.org/PyGObject)) * [Avahi](http://www.avahi.org) (optional) * [python-keyring](http://pypi.python.org/pypi/keyring) (optional) From e976e05efea9102ede199284a1afc1053ec28fd3 Mon Sep 17 00:00:00 2001 From: coderkun Date: Wed, 18 Jan 2023 17:25:29 +0100 Subject: [PATCH 04/10] Fix setting sort order on Library panel (close #91) --- src/librarypanel.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librarypanel.py b/src/librarypanel.py index 2626c7b..7d325dd 100644 --- a/src/librarypanel.py +++ b/src/librarypanel.py @@ -114,6 +114,12 @@ class LibraryToolbar(Gtk.ButtonBox): self.select_button.set_active(False) + def set_sort_order(self, sort): + button = self._toolbar_sort_buttons[sort] + if button and not button.get_active(): + button.set_active(True) + + @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-panel.ui') @@ -389,11 +395,9 @@ class LibraryPanel(Gtk.Stack): def set_sort_order(self, sort): if self._sort_order != sort: - button = self._toolbar_sort_buttons[sort] - if button and not button.get_active(): - button.set_active(True) - self._sort_order = sort - self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order) + self._toolbar.set_sort_order(sort) + self._sort_order = sort + self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order) def get_sort_order(self): From 44fb332c62c0677b74e739d7b3ea02e6113ae3d2 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sat, 21 Jan 2023 12:59:01 +0100 Subject: [PATCH 05/10] =?UTF-8?q?Read=20cover=20with1=20=E2=80=9Creadpictu?= =?UTF-8?q?re=E2=80=9D=20command=20if=20=E2=80=9Calbumart=E2=80=9D=20is=20?= =?UTF-8?q?not=20found=20(close=20#90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client.py | 109 +++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/src/client.py b/src/client.py index cc043d8..5cc0b11 100644 --- a/src/client.py +++ b/src/client.py @@ -650,57 +650,25 @@ class Client(Base): def _get_albumart(self, album): - data = None if album in self._albums: album = self._albums[album] - if not album.get_tracks(): - return (album, None) self._logger.debug("get albumart for album \"%s\"", album.get_title()) - size = 1 - offset = 0 - index = 0 - # Read data until size is reached - try: - while offset < size: - self._write('albumart', args=[album.get_tracks()[0].get_file(), offset]) + # Use "albumart" command + if album.get_tracks(): + try: + return (album, self._read_binary('albumart', album.get_tracks()[0].get_file(), False)) + except CommandException as e: + # The "albumart" command throws an exception if not found + if e.get_error_number() != Client.PROTOCOL_ERROR_NOEXISTS: + raise e + # If no albumart can be found, use "readpicture" command + for track in album.get_tracks(): + data = self._read_binary('readpicture', track.get_file(), True) + if data: + return (album, data) - # Read first line which tells us whether there is an albumart - line = self._read_line() - if line.startswith(Client.PROTOCOL_ERROR): - error = line[len(Client.PROTOCOL_ERROR):].strip() - self._logger.debug("command failed: %r", error) - raise CommandException(error) - # First line is the file size - size = int(self._parse_dict([line])['size']) - self._logger.debug("size: %d", size) - # Second line is the count of bytes read - binary = int(self._parse_dict([self._read_line()])['binary']) - self._logger.debug("binary: %d", binary) - - # Create new data array on the first iteration - if not data: - data = bytearray(size) - # Create a view for the current chunk of data - data_view = memoryview(data)[offset:offset+binary] - # Read actual bytes - self._read_bytes(data_view, binary) - offset += binary - # Read line break to complete previous repsonse - self._read_line() - # Read command completion - end = self._read_line() - if not end.startswith(Client.PROTOCOL_COMPLETION): - self._logger.debug("albumart not completed") - data = None - break - except CommandException as e: - # If no albumart can be found, do not throw an exception - if e.get_error_number() == Client.PROTOCOL_ERROR_NOEXISTS: - data = None - else: - raise e - return (album, data) + return (album, None) def _get_custom(self, name): @@ -844,6 +812,55 @@ class Client(Base): return None + def _read_binary(self, command, filename, has_mimetype): + data = None + size = 1 + offset = 0 + index = 0 + + # Read data until size is reached + while offset < size: + self._write(command, args=[filename, offset]) + + # Read first line + line = self._read_line() + # Check first line for error + if line.startswith(Client.PROTOCOL_ERROR): + error = line[len(Client.PROTOCOL_ERROR):].strip() + self._logger.debug("command failed: %r", error) + raise CommandException(error) + # Check first line for completion + if line.startswith(Client.PROTOCOL_COMPLETION): + break + # First line is the file size + size = int(self._parse_dict([line])['size']) + self._logger.debug("size: %d", size) + # For some commands the second line is the mimetype + if has_mimetype: + mimetype = self._parse_dict([self._read_line()])['type'] + # Next line is the count of bytes read + binary = int(self._parse_dict([self._read_line()])['binary']) + self._logger.debug("binary: %d", binary) + + # Create new data array on the first iteration + if not data: + data = bytearray(size) + # Create a view for the current chunk of data + data_view = memoryview(data)[offset:offset+binary] + # Read actual bytes + self._read_bytes(data_view, binary) + offset += binary + # Read line break to complete previous repsonse + self._read_line() + # Read command completion + end = self._read_line() + if not end.startswith(Client.PROTOCOL_COMPLETION): + self._logger.debug("albumart not completed") + data = None + break + return data + + def _read_bytes(self, buf, nbytes): self._logger.debug("reading bytes") # Use already buffered data From bfb8eac62d8d3a39816989fdd7849c06a110f496 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sat, 21 Jan 2023 17:16:31 +0100 Subject: [PATCH 06/10] Bump version to 3.2 --- data/ui/info-dialog.ui | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/ui/info-dialog.ui b/data/ui/info-dialog.ui index 99b3524..d6c0ed8 100644 --- a/data/ui/info-dialog.ui +++ b/data/ui/info-dialog.ui @@ -10,7 +10,7 @@ dialog center CoverGrid - 3.1 + 3.2 CoverGrid is a client for the Music Player Daemon, focusing on albums instead of single tracks. http://www.suruatoel.xyz/codes/mcg xyz.suruatoel.mcg diff --git a/meson.build b/meson.build index d644865..1ce0af4 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mcg', - version: '3.1', + version: '3.2', meson_version: '>= 0.59.0', default_options: [ 'warning_level=2', From 21bd0f58321bd7b620c4ee385836bf051c761190 Mon Sep 17 00:00:00 2001 From: coderkun Date: Tue, 28 Feb 2023 12:55:26 +0100 Subject: [PATCH 07/10] Fix setting sort type on Library panel at startup (close #95) --- src/librarypanel.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librarypanel.py b/src/librarypanel.py index 7d325dd..938d0fe 100644 --- a/src/librarypanel.py +++ b/src/librarypanel.py @@ -120,6 +120,13 @@ class LibraryToolbar(Gtk.ButtonBox): button.set_active(True) + def set_sort_type(self, sort_type): + if sort_type: + self.toolbar_sort_order_button.set_active(True) + else: + self.toolbar_sort_order_button.set_active(False) + + @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-panel.ui') @@ -406,12 +413,11 @@ class LibraryPanel(Gtk.Stack): def set_sort_type(self, sort_type): if self._sort_type != sort_type: + self._toolbar.set_sort_type(sort_type) if sort_type: sort_type_gtk = Gtk.SortType.DESCENDING - self.toolbar_sort_order_button.set_active(True) else: sort_type_gtk = Gtk.SortType.ASCENDING - self.toolbar_sort_order_button.set_active(False) if self._sort_type != sort_type_gtk: self._sort_type = sort_type_gtk self._library_grid_model.set_sort_column_id(2, sort_type) From 6ba8bc550fe1f406db610e02d448271734788d6e Mon Sep 17 00:00:00 2001 From: coderkun Date: Tue, 28 Feb 2023 13:18:07 +0100 Subject: [PATCH 08/10] Bump version to 3.2.1 --- data/ui/info-dialog.ui | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/ui/info-dialog.ui b/data/ui/info-dialog.ui index d6c0ed8..bdd14f2 100644 --- a/data/ui/info-dialog.ui +++ b/data/ui/info-dialog.ui @@ -10,7 +10,7 @@ dialog center CoverGrid - 3.2 + 3.2.1 CoverGrid is a client for the Music Player Daemon, focusing on albums instead of single tracks. http://www.suruatoel.xyz/codes/mcg xyz.suruatoel.mcg diff --git a/meson.build b/meson.build index 1ce0af4..5a6d445 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mcg', - version: '3.2', + version: '3.2.1', meson_version: '>= 0.59.0', default_options: [ 'warning_level=2', From 1b4885bd206c2ae6a11170f8ac7f2761e152ac70 Mon Sep 17 00:00:00 2001 From: coderkun Date: Sun, 8 Jan 2023 18:20:30 +0100 Subject: [PATCH 09/10] =?UTF-8?q?Port=20UI=20to=20GTK=E2=80=AF4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/gtk.css | 53 +- data/ui/album-headerbar.ui | 16 +- data/ui/connection-panel.ui | 256 +++----- data/ui/cover-panel.ui | 342 +++++------ data/ui/cover-toolbar.ui | 33 -- data/ui/gtk.menu.ui | 75 --- data/ui/info-dialog.ui | 46 -- data/ui/library-panel.ui | 579 +++++++++--------- data/ui/library-toolbar.ui | 232 -------- data/ui/playlist-panel.ui | 342 ++++++----- data/ui/playlist-toolbar.ui | 55 -- data/ui/server-panel.ui | 847 ++++++++++----------------- data/ui/server-toolbar.ui | 14 - data/ui/shortcuts-dialog.ui | 21 +- data/ui/window.ui | 299 +++------- data/xyz.suruatoel.mcg.gresource.xml | 7 +- src/albumheaderbar.py | 7 +- src/application.py | 65 +- src/client.py | 12 +- src/connectionpanel.py | 79 ++- src/coverpanel.py | 115 ++-- src/infodialog.py | 15 - src/librarypanel.py | 505 ++++++---------- src/main.py | 2 - src/meson.build | 1 - src/playlistpanel.py | 184 +++--- src/serverpanel.py | 29 +- src/shortcutsdialog.py | 4 +- src/utils.py | 48 +- src/window.py | 203 +++---- 30 files changed, 1674 insertions(+), 2812 deletions(-) delete mode 100644 data/ui/cover-toolbar.ui delete mode 100644 data/ui/gtk.menu.ui delete mode 100644 data/ui/info-dialog.ui delete mode 100644 data/ui/library-toolbar.ui delete mode 100644 data/ui/playlist-toolbar.ui delete mode 100644 data/ui/server-toolbar.ui delete mode 100644 src/infodialog.py diff --git a/data/gtk.css b/data/gtk.css index 469b262..1b361de 100644 --- a/data/gtk.css +++ b/data/gtk.css @@ -1,8 +1,20 @@ -.bg-texture { +#content_stack { box-shadow:inset 4px 4px 10px rgba(0,0,0,0.3); background-image:url('noise-texture.png'); } +#port_spinner { + background:none; + margin-top:-13px; +} +#port_spinner text { + padding-left: 0; +} + +#server_stack_sidebar { + background-color:alpha(@theme_bg_color, 1); +} + .no-bg { background:none; } @@ -18,13 +30,17 @@ font-weight:bold; } -revealer.sidebar > * { - background-color:alpha(@theme_bg_color, 0.8); - box-shadow:0 0 10px @theme_bg_color; - margin-left:20px +window.fullscreen #cover_box { + background: black; } -revealer.sidebar scale mark indicator { +#cover_info_revealer { + background-color:alpha(@theme_bg_color, 0.8); + box-shadow:0 0 10px @theme_bg_color; + margin-left:20px; +} + +#cover_info_revealer scale mark indicator { margin-right:5px; } @@ -32,24 +48,13 @@ actionbar { background-color:@theme_unfocused_bg_color; } -/* Icon View in regular mode */ -iconview.view:selected, -iconview.view:selected:focus { - background-color:@theme_selected_bg_color; +gridview child { + padding: 1px; } -iconview.view:hover { - -gtk-icon-effect:highlight; +gridview.selection child { + opacity: 0.5; } - -/* Icon View in selection mode */ -iconview.view.selection { - -gtk-icon-effect:dim; -} -iconview.view.selection:selected, -iconview.view.selection:selected:focus { - background-color:@theme_selected_bg_color; - -gtk-icon-effect:highlight; -} -iconview.view.selection:hover { - -gtk-icon-effect:none; +gridview.selection child:hover, +gridview.selection child:selected { + opacity: 1; } diff --git a/data/ui/album-headerbar.ui b/data/ui/album-headerbar.ui index 76ade01..376c07c 100644 --- a/data/ui/album-headerbar.ui +++ b/data/ui/album-headerbar.ui @@ -1,8 +1,10 @@ - - - diff --git a/data/ui/connection-panel.ui b/data/ui/connection-panel.ui index f388d43..de6bf0c 100644 --- a/data/ui/connection-panel.ui +++ b/data/ui/connection-panel.ui @@ -1,182 +1,86 @@ - - - - - 1024 - 9999 - 6600 - 1 - 100 - - diff --git a/data/ui/cover-panel.ui b/data/ui/cover-panel.ui index 304d9d0..c4557f2 100644 --- a/data/ui/cover-panel.ui +++ b/data/ui/cover-panel.ui @@ -1,199 +1,159 @@ - - - + + + diff --git a/data/ui/cover-toolbar.ui b/data/ui/cover-toolbar.ui deleted file mode 100644 index 7d3fcdd..0000000 --- a/data/ui/cover-toolbar.ui +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - diff --git a/data/ui/gtk.menu.ui b/data/ui/gtk.menu.ui deleted file mode 100644 index b944502..0000000 --- a/data/ui/gtk.menu.ui +++ /dev/null @@ -1,75 +0,0 @@ - - - -
- - win.connect - Connect - <Primary>c - - - win.play - Play - <Primary>p - - - win.clear-playlist - Clear Playlist - <Primary>r - - - win.toggle-fullscreen - Toggle Fullscreen - F11 - - - win.search-library - Search Library - <Primary>f - -
-
- - win.panel - Connection - 0 - <Primary>KP_1 - - - win.panel - Cover - 1 - <Primary>KP_2 - - - win.panel - Playlist - 2 - <Primary>KP_3 - - - win.panel - Library - 3 - <Primary>KP_4 - -
-
- - win.show-help-overlay - Keyboard Shortcuts - <Primary>k - - - app.info - Info - <Primary>i - - - app.quit - Quit - <Primary>q - -
-
-
diff --git a/data/ui/info-dialog.ui b/data/ui/info-dialog.ui deleted file mode 100644 index 99b3524..0000000 --- a/data/ui/info-dialog.ui +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - diff --git a/data/ui/library-panel.ui b/data/ui/library-panel.ui index 0e499d9..c459cd0 100644 --- a/data/ui/library-panel.ui +++ b/data/ui/library-panel.ui @@ -1,303 +1,332 @@ - - - diff --git a/data/ui/library-toolbar.ui b/data/ui/library-toolbar.ui deleted file mode 100644 index 97cad01..0000000 --- a/data/ui/library-toolbar.ui +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - 100 - 1000 - 150 - 1 - 10 - - - False - - - True - False - vertical - - - 350 - True - True - grid_adjustment - False - -1 - 0 - 0 - False - - - - - True - True - 0 - - - - - gtk-refresh - True - True - True - none - True - - - - False - True - 1 - - - - - True - False - vertical - - - True - False - vertical - - - False - True - 0 - - - - - True - False - Sort - - - False - True - 1 - - - - - sort by artist - True - True - False - True - sort_year - - - - False - True - 2 - - - - - sort by title - True - True - False - True - sort_year - - - - False - True - 3 - - - - - sort by year - True - True - False - True - True - - - - False - True - 4 - - - - - gtk-sort-descending - True - True - False - True - True - True - - - - False - True - 5 - - - - - False - True - 2 - - - - - - - diff --git a/data/ui/playlist-panel.ui b/data/ui/playlist-panel.ui index 9ee8b7a..8796afc 100644 --- a/data/ui/playlist-panel.ui +++ b/data/ui/playlist-panel.ui @@ -1,194 +1,182 @@ - - - diff --git a/data/ui/playlist-toolbar.ui b/data/ui/playlist-toolbar.ui deleted file mode 100644 index 843625c..0000000 --- a/data/ui/playlist-toolbar.ui +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - diff --git a/data/ui/server-panel.ui b/data/ui/server-panel.ui index 333919d..91ffe99 100644 --- a/data/ui/server-panel.ui +++ b/data/ui/server-panel.ui @@ -1,547 +1,326 @@ - - - diff --git a/data/ui/server-toolbar.ui b/data/ui/server-toolbar.ui deleted file mode 100644 index c1857a4..0000000 --- a/data/ui/server-toolbar.ui +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/data/ui/shortcuts-dialog.ui b/data/ui/shortcuts-dialog.ui index 8109201..279c992 100644 --- a/data/ui/shortcuts-dialog.ui +++ b/data/ui/shortcuts-dialog.ui @@ -1,9 +1,10 @@ - + +