PLUGIN_NAME = "Show Only Selected Albums"
PLUGIN_AUTHOR = "Echelon"
PLUGIN_DESCRIPTION = "Shows only selected album types from the selection in the right Picard panel"
PLUGIN_VERSION = '0.1'
PLUGIN_API_VERSIONS = ['2.2']
PLUGIN_LICENSE = "GPL-2.0-or-later"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.html"
from PyQt5 import QtGui
from PyQt5.QtWidgets import QLabel, QGridLayout, QWidget, QCheckBox
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtCore import QCoreApplication
from picard.ui.itemviews import BaseAction, register_album_action
showwindow = QWidget()
showwindow.setStyleSheet("font-size:12pt;")
grid = QGridLayout()
showwindow.setLayout(grid)
showwindow.setGeometry(1500, 200, 400, 150)
showwindow.setWindowTitle("Show Albums")
showwindow.setWindowIcon(QtGui.QIcon(":/images/16x16/org.musicbrainz.Picard.png"))
ckbox1 = QCheckBox("Show only this album")
ckbox2 = QCheckBox("Show only this album")
ckbox3 = QCheckBox("Show only this album")
ckbox4 = QCheckBox("Show only this album")
ckbox5 = QCheckBox("Show only this album")
grid.addWidget(ckbox1, 0, 0)
grid.addWidget(ckbox2, 1, 0)
grid.addWidget(ckbox3, 2, 0)
grid.addWidget(ckbox4, 3, 0)
grid.addWidget(ckbox5, 4, 0)
icon1 = QLabel()
icon1.setPixmap(QPixmap(":/images/22x22/media-optical.png"))
icon2 = QLabel()
icon2.setPixmap(QPixmap(":/images/22x22/media-optical-modified.png"))
icon3 = QLabel()
icon3.setPixmap(QPixmap(":/images/22x22/media-optical-saved.png"))
icon4 = QLabel()
icon4.setPixmap(QPixmap(":/images/22x22/media-optical-saved-modified.png"))
icon5 = QLabel()
icon5.setPixmap(QPixmap(":/images/22x22/media-optical-error.png"))
grid.addWidget(icon1, 0, 1)
grid.addWidget(icon2, 1, 1)
grid.addWidget(icon3, 2, 1)
grid.addWidget(icon4, 3, 1)
grid.addWidget(icon5, 4, 1)
class ShowAlbums(BaseAction):
NAME = 'Show albums'
def callback(self, objs):
if ckbox1.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
pass
else:
pass
else:
if album.is_modified():
pass
else:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if ckbox2.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
pass
else:
pass
else:
if album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
else:
pass
if ckbox3.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
pass
else:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
else:
if album.is_modified():
pass
else:
pass
if ckbox4.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
else:
pass
else:
if album.is_modified():
pass
else:
pass
if ckbox5.isChecked():
pass
else:
for album in objs:
if album.errors:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
elif album.is_complete():
if album.is_modified():
pass
else:
pass
else:
if album.is_modified():
pass
else:
pass
showwindow.show()
register_album_action(ShowAlbums())
This is a effectively a review comment on your code based on an assumption that you used an AI coding assistant to create the code (though IME relatively inexperienced coders often copy and paste a lot of boiler plate code rather than finding a more readable and aesthetic means of achieving the same results).
But @derat does have a point here. These deeply nested if structures are generally considered to be a fairly bad programming style which is difficult to read, easy to introduce bugs into etc.
So here are my code comments on this plugin:
Again, well done for writing something that works and is useful.
My biggest gripe is that this does NOT Show (or Hide) albums of a particular type as it describes itself, but instead it actually removes them from Picard (like Remove Perfect Albums does). TBH if it removes albums rather than hides / shows them, then I am not sure what benefit it really provides over and above Remove Perfect Albums (because the complete and unchanged / saved ones are typically going to be the majority of the albums you want to delete in most cases).
I don’t think this plugin actually works the way I would expect it to. I am sure that you have tested it, and that it works the way you wrote it, however I would expect to open the popup (which would be initialised when Picard starts with all checkboxes checked), and by clicking on the checkboxes I would dynamically either show or hide particular types of albums from the tree. To achieve this you actually need to hook a callback to each checkbox, which then processes the tree when the value changes, and uses QT calls to hide or show the entries…
It wouldn’t quite be the same functionality, but if you made it work this way, then you could have 2 checkboxes for Complete/Incomplete and Unchanged/changed which work in combination (plus a 3rd for error).
The big nested / indented code section has a few issues IMO:
6. I think you need to process all the albums in the tree, not just the selected ones.
7. The loop should be outside all the ifs, and the logic should probably be an a method of its own, and perhaps each option should call some sort of generic sub-method to avoid code duplication, perhaps passing a callable which can be used to check whether criteria are met.
So sorry, I think this plugin needs some more significant changes before it is ready to be included in the plugins list.
But don’t be disheartened - I think this can also be a useful plugin, but there is a bit more of a learning curve for you to climb before this is ready.
PLUGIN_NAME = "Show Only Selected Albums"
PLUGIN_AUTHOR = "Echelon"
PLUGIN_DESCRIPTION = "Shows only selected album types from the selection in the right Picard panel"
PLUGIN_VERSION = '0.2'
PLUGIN_API_VERSIONS = ['2.2']
PLUGIN_LICENSE = "GPL-2.0-or-later"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.html"
from PyQt5 import QtGui
from PyQt5.QtWidgets import QLabel, QGridLayout, QWidget, QCheckBox
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtCore import QCoreApplication
from picard.ui.itemviews import BaseAction, register_album_action
showwindow = QWidget()
showwindow.setStyleSheet("font-size:12pt;")
grid = QGridLayout()
showwindow.setLayout(grid)
showwindow.setGeometry(1500, 200, 400, 150)
showwindow.setWindowTitle("Show Albums")
showwindow.setWindowIcon(QtGui.QIcon(":/images/16x16/org.musicbrainz.Picard.png"))
ckbox1 = QCheckBox("Show only this album")
ckbox2 = QCheckBox("Show only this album")
ckbox3 = QCheckBox("Show only this album")
ckbox4 = QCheckBox("Show only this album")
ckbox5 = QCheckBox("Show only this album")
grid.addWidget(ckbox1, 0, 0)
grid.addWidget(ckbox2, 1, 0)
grid.addWidget(ckbox3, 2, 0)
grid.addWidget(ckbox4, 3, 0)
grid.addWidget(ckbox5, 4, 0)
icon1 = QLabel()
icon1.setPixmap(QPixmap(":/images/22x22/media-optical.png"))
icon2 = QLabel()
icon2.setPixmap(QPixmap(":/images/22x22/media-optical-modified.png"))
icon3 = QLabel()
icon3.setPixmap(QPixmap(":/images/22x22/media-optical-saved.png"))
icon4 = QLabel()
icon4.setPixmap(QPixmap(":/images/22x22/media-optical-saved-modified.png"))
icon5 = QLabel()
icon5.setPixmap(QPixmap(":/images/22x22/media-optical-error.png"))
grid.addWidget(icon1, 0, 1)
grid.addWidget(icon2, 1, 1)
grid.addWidget(icon3, 2, 1)
grid.addWidget(icon4, 3, 1)
grid.addWidget(icon5, 4, 1)
class ShowAlbums(BaseAction):
NAME = 'Show albums'
def callback(self, objs):
if ckbox1.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
else:
if album.is_modified():
pass
else:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if ckbox2.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
else:
if album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
else:
pass
if ckbox3.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
pass
else:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if ckbox4.isChecked():
pass
else:
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
else:
pass
if ckbox5.isChecked():
pass
else:
for album in objs:
if album.errors:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
showwindow.show()
register_album_action(ShowAlbums())
PLUGIN_NAME = "Show Only Selected Albums"
PLUGIN_AUTHOR = "Echelon"
PLUGIN_DESCRIPTION = "Shows only selected album types from the selection in the right Picard panel"
PLUGIN_VERSION = '0.3'
PLUGIN_API_VERSIONS = ['2.2']
PLUGIN_LICENSE = "GPL-2.0-or-later"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.html"
from PyQt5.QtWidgets import QLabel, QGridLayout, QWidget, QCheckBox
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtCore import QCoreApplication
from picard.ui.itemviews import BaseAction, register_album_action
showwindow = QWidget()
showwindow.setStyleSheet("font-size:12pt;")
grid = QGridLayout()
showwindow.setLayout(grid)
showwindow.setGeometry(200, 200, 400, 150)
showwindow.setWindowTitle("Show Albums")
showwindow.setWindowIcon(QIcon(":/images/16x16/org.musicbrainz.Picard.png"))
ckbox1 = QCheckBox(" Show only this album")
ckbox2 = QCheckBox(" Show only this album")
ckbox3 = QCheckBox(" Show only this album")
ckbox4 = QCheckBox(" Show only this album")
ckbox5 = QCheckBox(" Show only this album")
grid.addWidget(ckbox1, 0, 0)
grid.addWidget(ckbox2, 1, 0)
grid.addWidget(ckbox3, 2, 0)
grid.addWidget(ckbox4, 3, 0)
grid.addWidget(ckbox5, 4, 0)
icon1 = QLabel()
icon1.setPixmap(QPixmap(":/images/22x22/media-optical.png"))
icon2 = QLabel()
icon2.setPixmap(QPixmap(":/images/22x22/media-optical-modified.png"))
icon3 = QLabel()
icon3.setPixmap(QPixmap(":/images/22x22/media-optical-saved.png"))
icon4 = QLabel()
icon4.setPixmap(QPixmap(":/images/22x22/media-optical-saved-modified.png"))
icon5 = QLabel()
icon5.setPixmap(QPixmap(":/images/22x22/media-optical-error.png"))
grid.addWidget(icon1, 0, 1)
grid.addWidget(icon2, 1, 1)
grid.addWidget(icon3, 2, 1)
grid.addWidget(icon4, 3, 1)
grid.addWidget(icon5, 4, 1)
class ShowAlbums(BaseAction):
NAME = 'Show albums'
def callback(self, objs):
if not ckbox1.isChecked():
for album in objs:
if album.errors:
pass
elif album.is_complete():
pass
else:
if not album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if not ckbox2.isChecked():
for album in objs:
if album.errors:
pass
elif album.is_complete():
pass
else:
if album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if not ckbox3.isChecked():
for album in objs:
if album.errors:
pass
elif album.is_complete():
if not album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if not ckbox4.isChecked():
for album in objs:
if album.errors:
pass
elif album.is_complete():
if album.is_modified():
self.tagger.remove_album(album)
QCoreApplication.processEvents()
if not ckbox5.isChecked():
for album in objs:
if album.errors:
self.tagger.remove_album(album)
QCoreApplication.processEvents()
showwindow.show()
register_album_action(ShowAlbums())
I have suggested to you before in your topic here for your first proposed plugin Statistics that the route to get a plugin published is via the plugins repo, and indeed you have submitted a PR there for it - so I have no idea why you have now decided to try to get your second plugin published via the wiki page that you refer to which is very old and that is no longer the normal route for publishing plugins.
I have also made detailed code review comments on both your earlier versions of this plugin (see above) and on your other proposed plugin, and indeed for your other plugin attempt I went out of my way to try to help you get your plugin code up to the standard needed for it to be published, even rewriting the code for you when you said that doing so yourself was too difficult for you, and all I got in return from you was abuse.
This code quality in this plugin is at least as bad as your other plugin, and whilst I could spend time trying to help you with this one, I see no reason to do so after the way you behaved last time.
To be bluntly honest with you I think you have 2 options open to you for both this plugin and your previous one:
Learn from the review comments being made about your code, and use them to improve the quality of your code, including submitting this plugin as a PR if you want it published. I have even given you a rewritten version of your other plugin as a means to compare your code with mine and learn how to write more elegant code - and I previously offered it without asking for any attribution (though I now regret that). (My code is almost certainly not perfect - so you could probably improve on it still further.)
Programme these plugins just for your own use - providing they work, the code quality is far less important if the plugins are not publicly published.
Note to other readers: Except for one of @Peter69’s posts on the other plugin’s topic that was reported for abuse (by someone else I think - it was a month ago so my memory is hazy), the entire conversations regarding both this plugin and the previous one are available above or on the links given - thus you can form your own judgements.