Added check to ensure that TODOs all have an associated issue

This commit is contained in:
Sumner Evans
2020-02-20 20:45:37 -07:00
parent a160d6dbaa
commit a90217cd24
18 changed files with 157 additions and 127 deletions

View File

@@ -21,7 +21,7 @@ lint:
- pipenv run python setup.py check -mrs
- pipenv run flake8
- pipenv run mypy sublime
- ./cicd/no_print.sh
- pipenv run cicd/custom_style_check.py
test:
stage: test

View File

@@ -6,7 +6,7 @@ v0.8.12
* When album cover art is not provided by the server, a default album art image
is used (Contributed by @sentriz.)
* **New Setting**: *Serve locally cached files over the LAN to Chromecast
devices.*: If checked, a local server will be started on your computer which
devices*: If checked, a local server will be started on your computer which
will serve your locally cached music files to the Chromecast. If not checked,
the Chromecast will always stream from the server.
* When serving local files, the internal server now only exposes one song at a

View File

@@ -93,7 +93,7 @@ yourself with the following commands::
$ flake8
$ mypy sublime
$ ./cicd/no_print.sh
$ ./cicd/custom_style_check.py
CI/CD Pipeline
--------------

View File

@@ -18,6 +18,7 @@ graphviz = "*"
sphinx = "*"
sphinx-rtd-theme = "*"
sphinx-autodoc-typehints = "*"
termcolor = "*"
[packages]
sublime-music = {editable = true,path = "."}

116
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "92334bdb9b3d73608941dce1ab826f8619e44a0aa85d7c33f1045f5467810cb0"
"sha256": "c16627b97b66d2ad7016bd43428e26f5f29836ba28eb797d27c4cc80f8a70a99"
},
"pipfile-spec": 6,
"requires": {
@@ -39,41 +39,36 @@
},
"cffi": {
"hashes": [
"sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42",
"sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04",
"sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5",
"sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54",
"sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba",
"sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57",
"sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396",
"sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12",
"sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97",
"sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43",
"sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db",
"sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3",
"sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b",
"sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579",
"sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346",
"sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159",
"sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652",
"sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e",
"sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a",
"sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506",
"sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f",
"sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d",
"sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c",
"sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20",
"sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858",
"sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc",
"sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a",
"sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3",
"sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e",
"sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410",
"sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25",
"sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b",
"sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d"
"sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff",
"sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b",
"sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac",
"sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0",
"sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384",
"sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26",
"sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6",
"sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b",
"sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e",
"sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd",
"sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2",
"sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66",
"sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc",
"sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8",
"sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55",
"sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4",
"sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5",
"sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d",
"sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78",
"sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa",
"sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793",
"sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f",
"sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a",
"sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f",
"sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30",
"sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f",
"sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3",
"sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"
],
"version": "==1.13.2"
"version": "==1.14.0"
},
"chardet": {
"hashes": [
@@ -124,17 +119,17 @@
},
"fuzzywuzzy": {
"hashes": [
"sha256:5ac7c0b3f4658d2743aa17da53a55598144edbc5bee3c6863840636e6926f254",
"sha256:6f49de47db00e1c71d40ad16da42284ac357936fa9b66bea1df63fed07122d62"
"sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8",
"sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"
],
"version": "==0.17.0"
"version": "==0.18.0"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
"sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
"sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
],
"version": "==2.8"
"version": "==2.9"
},
"ifaddr": {
"hashes": [
@@ -188,9 +183,9 @@
},
"pycairo": {
"hashes": [
"sha256:4f5ba9374a46c98729dd3727d993f5e17ed0286fd6738ed464fe4efa0612d19c"
"sha256:2c143183280feb67f5beb4e543fd49990c28e7df427301ede04fc550d3562e84"
],
"version": "==1.19.0"
"version": "==1.19.1"
},
"pychromecast": {
"hashes": [
@@ -248,10 +243,10 @@
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
"sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee",
"sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"
],
"version": "==2.22.0"
"version": "==2.23.0"
},
"secretstorage": {
"hashes": [
@@ -281,9 +276,9 @@
},
"wrapt": {
"hashes": [
"sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1"
"sha256:0ec40d9fd4ec9f9e3ff9bdd12dbd3535f4085949f4db93025089d7a673ea94e8"
],
"version": "==1.11.2"
"version": "==1.12.0"
},
"zeroconf": {
"hashes": [
@@ -405,10 +400,10 @@
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
"sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
"sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
],
"version": "==2.8"
"version": "==2.9"
},
"imagesize": {
"hashes": [
@@ -626,10 +621,10 @@
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
"sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee",
"sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"
],
"version": "==2.22.0"
"version": "==2.23.0"
},
"rope": {
"hashes": [
@@ -664,11 +659,11 @@
},
"sphinx": {
"hashes": [
"sha256:298537cb3234578b2d954ff18c5608468229e116a9757af3b831c2b2b4819159",
"sha256:e6e766b74f85f37a5f3e0773a1e1be8db3fcb799deb58ca6d18b70b0b44542a5"
"sha256:525527074f2e0c2585f68f73c99b4dc257c34bbe308b27f5f8c7a6e20642742f",
"sha256:543d39db5f82d83a5c1aa0c10c88f2b6cff2da3e711aa849b2c627b4b403bbd9"
],
"index": "pypi",
"version": "==2.3.1"
"version": "==2.4.2"
},
"sphinx-autodoc-typehints": {
"hashes": [
@@ -728,6 +723,13 @@
],
"version": "==1.1.3"
},
"termcolor": {
"hashes": [
"sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"
],
"index": "pypi",
"version": "==1.1.0"
},
"typed-ast": {
"hashes": [
"sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355",

38
cicd/custom_style_check.py Executable file
View File

@@ -0,0 +1,38 @@
#! /usr/bin/env python
import sys
import re
from pathlib import Path
from termcolor import cprint
print_re = re.compile(r'print\(.*\)')
todo_re = re.compile(r'#\s*TODO:?\s*')
accounted_for_todo = re.compile(r'#\s*TODO:?\s*\((#\d+)\)')
def check_file(path):
print(f'Checking {path.absolute()}...')
file = path.open()
valid = True
for i, line in enumerate(file, start=1):
if print_re.search(line) and '# allowprint' not in line:
cprint(f'{i}: {line}', 'red', end='', attrs=['bold'])
valid = False
if todo_re.search(line) and not accounted_for_todo.search(line):
cprint(f'{i}: {line}', 'red', end='', attrs=['bold'])
valid = False
file.close()
return valid
valid = True
for path in Path('sublime').glob('**/*.py'):
valid &= check_file(path)
print()
sys.exit(0 if valid else 1)

View File

@@ -1,11 +0,0 @@
#! /bin/bash
grep -Inre "print(" sublime | while read line; do
if [[ $line =~ "# allowprint" ]]; then
continue
fi
echo "Found instance of print statement:"
echo $line
echo "Use logging instead or add '# allowprint' to the end of the line."
exit 1
done

View File

@@ -182,9 +182,7 @@ class SublimeMusicApp(Gtk.Application):
self.player = self.mpv_player
if self.state.current_device != 'this device':
# TODO figure out how to activate the chromecast if possible
# without blocking the main thread. Also, need to make it obvious
# that we are trying to connect.
# TODO (#120)
pass
self.state.current_device = 'this device'
@@ -193,7 +191,6 @@ class SublimeMusicApp(Gtk.Application):
self.player.volume = self.state.volume
# Prompt to load the play queue from the server.
# TODO should this be behind sync enabled?
if self.state.config.server.sync_enabled:
self.update_play_state_from_server(prompt_confirm=True)
@@ -532,7 +529,17 @@ class SublimeMusicApp(Gtk.Application):
self.state.current_album_sort = 'byGenre'
self.state.current_album_genre = album.genre
else:
# TODO message?
dialog = Gtk.MessageDialog(
transient_for=self.window,
message_type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.OK,
text='Could not go to album',
)
dialog.format_secondary_markup(
'Could not go to the album because it does not have a year or '
'genre.')
dialog.run()
dialog.destroy()
return
self.state.current_tab = 'albums'
@@ -740,7 +747,8 @@ class SublimeMusicApp(Gtk.Application):
GLib.idle_add(lambda: self.window.update(self.state, force=force))
def update_play_state_from_server(self, prompt_confirm=False):
# TODO need to make the up next list loading for the duration here
# TODO (#129): need to make the up next list loading for the duration
# here if prompt_confirm is False.
was_playing = self.state.playing
self.player.pause()
self.state.playing = False
@@ -824,12 +832,6 @@ class SublimeMusicApp(Gtk.Application):
# Show a song play notification.
if self.state.config.song_play_notification:
# TODO someone needs to test this, Dunst doesn't seem to
# support it.
def on_notification_click(*args):
self.window.present()
try:
notification_lines = []
if song.album:
@@ -843,7 +845,7 @@ class SublimeMusicApp(Gtk.Application):
song_notification.add_action(
'clicked',
'Open Sublime Music',
on_notification_click,
lambda *a: self.window.present(),
)
song_notification.show()

View File

@@ -294,7 +294,7 @@ class CacheManager(metaclass=Singleton):
# The server instance.
server: Server
# TODO need to split out the song downloads and make them higher
# TODO (#56): need to split out the song downloads and make them higher
# priority I think. Maybe even need to just make this a priority queue.
download_set_lock = threading.Lock()
current_downloads: Set[str] = set()
@@ -438,8 +438,6 @@ class CacheManager(metaclass=Singleton):
# The resource is already being downloaded. Busy loop until
# it has completed. Then, just return the path to the
# resource.
# TODO: figure out a way to determine if the download we
# are waiting on failed.
while abs_path_str in self.current_downloads:
sleep(0.2)
else:
@@ -783,7 +781,7 @@ class CacheManager(metaclass=Singleton):
)
def invalidate_album_list(self, type_):
# TODO make this invalidate instead of delete
# TODO (#24): make this invalidate instead of delete
cache_name = 'albums'
if not self.cache.get(cache_name, {}).get(type_):
return
@@ -1010,8 +1008,6 @@ class CacheManager(metaclass=Singleton):
return
# Server Results
# TODO: spawn another future to get the search results from
# self.server.search2
search_fn = self.server.search3
try:
# Attempt to add the server search results to the

View File

@@ -67,7 +67,7 @@ class DBusManager:
self.on_set_property,
)
# TODO: I have no idea what to do here.
# TODO (#127): I have no idea what to do here.
def dbus_name_lost(*args):
pass
@@ -103,7 +103,7 @@ class DBusManager:
params,
invocation,
):
# TODO I don't even know if this works.
# TODO (#127): I don't even know if this works.
if interface == 'org.freedesktop.DBus.Properties':
if method == 'Get':
invocation.return_value(
@@ -260,8 +260,6 @@ class DBusManager:
'CanEditTracks': False,
},
'org.mpris.MediaPlayer2.Playlists': {
# TODO this may do a network request. This really is a case for
# doing the whole thing with caching some data beforehand.
'PlaylistCount': playlist_count,
'Orderings': ['Alphabetical', 'Created', 'Modified'],
'ActivePlaylist': ('(b(oss))', active_playlist),

View File

@@ -315,10 +315,10 @@ class ChromecastPlayer(Player):
self.on_new_media_status)
# Set host_ip
# TODO should have a mechanism to update this. Maybe it should be
# determined every time we try and play a song.
# TODO does not work properyfly when on VPNs when the DNS is piped over
# the VPN tunnel.
# TODO (#128): should have a mechanism to update this. Maybe it should
# be determined every time we try and play a song.
# TODO (#129): does not work properly when on VPNs when the DNS is
# piped over the VPN tunnel.
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))

View File

@@ -113,7 +113,7 @@ class Server:
verify=not self.disable_cert_verify,
# timeout=timeout,
)
# TODO make better
# TODO (#122): make better
if result.status_code != 200:
raise Exception(f'[FAIL] get: {url} status={result.status_code}')
@@ -136,7 +136,7 @@ class Server:
result = self._get(url, **params)
subsonic_response = result.json()['subsonic-response']
# TODO make better
# TODO (#122): make better
if not subsonic_response:
raise Exception('Fail!')
@@ -158,7 +158,7 @@ class Server:
def do_download(self, url, **params) -> bytes:
download = self._get(url, **params)
if 'json' in download.headers.get('Content-Type'):
# TODO make better
# TODO (#122): make better
raise Exception("Didn't expect JSON.")
return download.content

View File

@@ -224,7 +224,7 @@ class AlbumsPanel(Gtk.Box):
try:
year = int(entry.get_text())
except Exception:
# TODO prevent input of non-numerals
# TODO (#123): prevent input of non-numerals
logging.error(
'failed, should do something to prevent non-numeric input')
return
@@ -496,7 +496,7 @@ class AlbumsGrid(Gtk.Overlay):
self.emit('cover-clicked', self.list_store[selected_index].id)
def on_grid_resize(self, flowbox, rect):
# TODO: this doesn't work with themes that add extra padding.
# TODO (#124): this doesn't work with themes that add extra padding.
# 200 + (10 * 2) + (5 * 2) = 230
# picture + (padding * 2) + (margin * 2)
new_items_per_row = min((rect.width // 230), 7)
@@ -578,8 +578,9 @@ class AlbumsGrid(Gtk.Overlay):
if force_reload_from_master:
# Just remove everything and re-add all of the items.
# TODO make this smarter somehow to avoid flicker. Maybe change
# this so that it removes one by one and adds back one by one.
# TODO (#114): make this smarter somehow to avoid flicker. Maybe
# change this so that it removes one by one and adds back one by
# one.
self.list_store_top.remove_all()
self.list_store_bottom.remove_all()
@@ -627,9 +628,9 @@ class AlbumsGrid(Gtk.Overlay):
self.detail_box_inner.pack_start(detail_element, True, True, 0)
self.detail_box.show_all()
# TODO scroll so that the grid_top is visible, and the detail_box
# is visible, with preference to the grid_top. May need to add
# another flag for this function.
# TODO (#88): scroll so that the grid_top is visible, and the
# detail_box is visible, with preference to the grid_top. May need
# to add another flag for this function.
else:
self.grid_top.unselect_all()
self.detail_box.hide()

View File

@@ -290,8 +290,6 @@ class ArtistDetailPanel(Gtk.Box):
order_token=self.update_order_token,
)
# TODO need to handle when this is force updated. Need to delete a bunch of
# stuff and un-cache things.
@util.async_callback(
lambda *a, **k: CacheManager.get_artist(*a, **k),
before_download=lambda self: self.set_all_loading(True),
@@ -311,8 +309,16 @@ class ArtistDetailPanel(Gtk.Box):
self.artist_name.set_markup(util.esc(f'<b>{artist.name}</b>'))
self.artist_stats.set_markup(self.format_stats(artist))
self.update_artist_info(artist.id, order_token=order_token)
self.update_artist_artwork(artist, order_token=order_token)
self.update_artist_info(
artist.id,
force=force,
order_token=order_token,
)
self.update_artist_artwork(
artist,
force=force,
order_token=order_token,
)
self.albums = artist.get('album', artist.get('child', []))
self.albums_list.update(artist)

View File

@@ -1,4 +1,4 @@
from typing import Union
from typing import List, Tuple, Union
import gi
@@ -74,7 +74,7 @@ class BrowsePanel(Gtk.Overlay):
)
self.spinner.hide()
def calculate_path(update_order_token):
def calculate_path(update_order_token) -> Tuple[List[str], int]:
if state.selected_browse_element_id is None:
return [], update_order_token

View File

@@ -67,7 +67,7 @@ class AlbumWithSongs(Gtk.Box):
album_title_and_buttons = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL)
# TODO: deal with super long-ass titles
# TODO (#43): deal with super long-ass titles
album_title_and_buttons.add(
Gtk.Label(
label=album.get('name', album.get('title')),
@@ -107,9 +107,6 @@ class AlbumWithSongs(Gtk.Box):
album.artist if show_artist_name else None,
album.year,
album.genre,
# TODO when not available (not browse by tags), calculate after the
# list loads and update the stats label.
util.format_sequence_duration(album.duration)
if album.get('duration') else None,
]

View File

@@ -96,14 +96,14 @@ class PlayerControls(Gtk.ActionBar):
state.current_song_index < len(state.play_queue) - 1)
# Repeat button state
# TODO: it's not correct to use symboloc vs. not symbolic icons for
# lighter/darker versions of the icon. Fix this by using FG color I
# TODO (#125): it's not correct to use symboloc vs. not symbolic icons
# for lighter/darker versions of the icon. Fix this by using FG color I
# think? But then we have to deal with styling, which sucks.
self.repeat_button.set_icon(state.repeat_type.icon)
# Shuffle button state
# TODO: it's not correct to use symboloc vs. not symbolic icons for
# lighter/darker versions of the icon. Fix this by using FG color I
# TODO (#125): it's not correct to use symboloc vs. not symbolic icons
# for lighter/darker versions of the icon. Fix this by using FG color I
# think? But then we have to deal with styling, which sucks.
self.shuffle_button.set_icon(
'media-playlist-shuffle'
@@ -131,7 +131,7 @@ class PlayerControls(Gtk.ActionBar):
self.editing = False
# Update the current song information.
# TODO add popup of bigger cover art photo here
# TODO (#126): add popup of bigger cover art photo here
if state.current_song is not None:
self.cover_art_update_order_token += 1
self.update_cover_art(
@@ -307,7 +307,7 @@ class PlayerControls(Gtk.ActionBar):
if self.play_queue_popover.is_visible():
self.play_queue_popover.popdown()
else:
# TODO scroll the currently playing song into view.
# TODO (#88): scroll the currently playing song into view.
self.play_queue_popover.popup()
self.play_queue_popover.show_all()

View File

@@ -370,9 +370,9 @@ class PlaylistDetailPanel(Gtk.Overlay):
return max(row_score(key, row) for row in rows)
def playlist_song_list_search_fn(model, col, key, treeiter, data=None):
# TODO: this is very inefficient, it's slow when the result is
# close to the bottom of the list. Would be good to research what
# the default one does (maybe it uses an index?).
# TODO (#28): this is very inefficient, it's slow when the result
# is close to the bottom of the list. Would be good to research
# what the default one does (maybe it uses an index?).
max_score = max_score_for_key(
key, tuple(tuple(row[1:4]) for row in model))
row_max_score = row_score(key, tuple(model[treeiter][1:4]))