Skip to content

Commit 4fc4044

Browse files
committed
v0.6.0
1 parent 771202e commit 4fc4044

File tree

7 files changed

+128
-53
lines changed

7 files changed

+128
-53
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ CHANGELOG
44
v0.5.4
55
------
66

7-
- [ ] Add preferences option for custom preview in main view
7+
- [x] Add Home/End for command line
8+
- [x] Use `set` command(to edit preferences) form main view
9+
- [x] Add preferences option for custom preview in main view
810

911

1012
v0.5.3

clid/_const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@
205205
'%y': 'date',
206206
'%l': 'album',
207207
'%t': 'title',
208-
'%n': 'track',
208+
# '%n': 'track',
209209
'%a': 'artist',
210210
'%c': 'comment',
211211
# '%g': 'genre',

clid/base.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@
66

77
import npyscreen as npy
88

9-
class ClidCommandLine(npy.ActionControllerSimple):
9+
class ClidActionController(npy.ActionControllerSimple):
1010
"""Base class for the command line at the bootom of the screen"""
1111

1212
def create(self):
1313
self.add_action('^:q$', self.exit_app, live=False) # quit with ':q'
14+
self.add_action('^:set .+', self.change_setting, live=False)
15+
1416

1517
def exit_app(self, command_line, widget_proxy, live):
1618
"""Exit the app with ':q'"""
1719
exit() # args are used internally by npyscreen
1820

21+
def change_setting(self, command_line, widget_proxy, live):
22+
"""Change a setting in the ini file"""
23+
pass # different for main and pref view; defined in respective files
1924

2025
class ClidTextfield(npy.wgtextbox.Textfield):
2126
def set_up_handlers(self):
@@ -29,5 +34,10 @@ def h_home(self, char):
2934
def h_end(self, char):
3035
self.cursor_position = len(self.value)
3136

37+
3238
class ClidTitleText(npy.TitleText):
3339
_entry_type = ClidTextfield
40+
41+
42+
class ClidCommandLine(npy.fmFormMuttActive.TextCommandBoxTraditional, ClidTextfield):
43+
pass # for making home and end keys work

clid/database.py

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
import stagger
99
import npyscreen
10-
import configobj
10+
11+
from . import _const
1112

1213
CONFIG = os.path.expanduser('~/.clid.ini')
1314

@@ -19,24 +20,45 @@ class Mp3DataBase(npyscreen.NPSFilteredDataBase):
1920
file_dict(dict):
2021
dict with the filename as key and absolute path to
2122
file as value. Used for displaying files and changing
22-
metadata
23+
metadata.
24+
settings(configobj.ConfigObj):
25+
used for accessing the ini file.
26+
pre_format(str):
27+
string with format specifiers used to display preview of
28+
files' tags.
29+
specifiers(list):
30+
list of format specifiers in pre_format
31+
meta_cache(dict):
32+
cache which holds the metadata of files as they are selected.
33+
2334
"""
2435
def __init__(self):
2536
super().__init__()
2637

27-
self.load_files_and_set_values() # set `file_dict` and `_values` attribute
28-
self.meta_cache = dict() # cache which holds the metadata of files as they are selected
38+
self.settings = None # set by main.ClidInterface
39+
self.file_dict = None
40+
self.meta_cache = dict()
2941

3042
# IDEA: set_values and set_search_list for updating values and search_list when refreshed
3143

44+
def filter_data(self):
45+
if self._filter and self._values:
46+
return [mp3 for mp3 in self.get_all_values() if self._filter in mp3.lower()]
47+
else:
48+
return self.get_all_values()
49+
50+
def load_preview_format(self):
51+
"""Make approriate varibles to hold preview formats"""
52+
self.pre_format = self.settings['preview_format']
53+
self.specifiers = _const.FORMAT_PAT.findall(self.pre_format)
3254

3355
def load_files_and_set_values(self):
3456
"""- Get a list of mp3 files in BASE_DIR recursively
3557
- Make a dict out of it
3658
- Assign it to `file_dict`
3759
- Set `_values` attribute
3860
"""
39-
base = configobj.ConfigObj(CONFIG)['music_dir']
61+
base = self.settings['music_dir']
4062

4163
ret_list = []
4264
for dir_tree in os.walk(base, followlinks=True): # get all mp3 files in the dir and sub-dirs
@@ -46,11 +68,6 @@ def load_files_and_set_values(self):
4668
self.file_dict = dict([(os.path.basename(abspath), abspath) for abspath in ret_list])
4769
self._values = tuple(sorted(self.file_dict.keys())) # sorted tuple of filenames
4870

49-
def filter_data(self):
50-
if self._filter and self._values:
51-
return [mp3 for mp3 in self.get_all_values() if self._filter in mp3.lower()]
52-
else:
53-
return self.get_all_values()
5471

5572
def parse_meta_for_status(self, filename):
5673
"""Make a string like 'artist - album - track_number. title' from a filename
@@ -61,16 +78,14 @@ def parse_meta_for_status(self, filename):
6178
"""
6279
if not filename in self.meta_cache:
6380
try:
64-
metadata = stagger.read_tag(self.file_dict[filename])
65-
self.meta_cache[filename] = '{art} - {alb} - {tno}. {title} '.format(
66-
art=metadata.artist,
67-
alb=metadata.album,
68-
# stagger saves track number as 0 if it is not given(won't be shown in players)
69-
tno=metadata.track if metadata.track != 0 else ' ',
70-
title=metadata.title
71-
)
81+
meta = stagger.read_tag(self.file_dict[filename])
82+
temp = self.pre_format # make a copy of format and replace specifiers with tags
83+
84+
for spec in self.specifiers:
85+
temp = temp.replace(spec, getattr(meta, _const.FORMAT[spec]))
86+
self.meta_cache[filename] = temp
7287
except stagger.errors.NoTagError:
73-
self.meta_cache[filename] = ' - - . '
88+
self.meta_cache[filename] = _const.FORMAT_PAT.sub('', self.specifiers)
7489

7590
return self.meta_cache[filename]
7691

@@ -82,9 +97,9 @@ class SettingsDataBase(object):
8297
"""Class to manage the settings/config file.
8398
8499
Attributes:
85-
_settings(configobj.ConfigObj):
100+
settings(configobj.ConfigObj):
86101
`ConfigObj` object for the clid.ini file
87-
parent(pref.PreferencesView):
102+
parent(npyscreen.FormMuttActiveTraditional):
88103
used to refer to parent form(pref.PreferencesView)
89104
disp_strings(list):
90105
list of formatted strings which will be used to display settings in the window
@@ -94,31 +109,36 @@ class SettingsDataBase(object):
94109
"""
95110
def __init__(self):
96111
self.parent = None # set by parent; see docstring
112+
self.settings = None # also set by parent
97113
self.when_changed = {
98114
'music_dir': self.music_dir,
99115
'preview_format': self.preview_format
100116
}
101117

102-
self._settings = configobj.ConfigObj(CONFIG)
103-
self.make_strings()
104118

105119
def make_strings(self):
106120
"""Make a list of strings which will be used to display the settings
107121
in the editing window
108122
"""
109-
self.disp_strings = [key + ' ' + value for key, value in self._settings.items()]
123+
self.disp_strings = [key + ' ' + value for key, value in self.settings.items()]
110124

111125
def change_setting(self, key, new):
112126
"""Change a setting in the clid.ini"""
113-
if key in self._settings:
114-
self._settings[key] = new
115-
self._settings.write()
127+
if key in self.settings:
128+
self.settings[key] = new
129+
self.settings.write()
116130
self.when_changed[key]()
117131

118132
def music_dir(self):
133+
"""To be executed when `music_dir` option is changed"""
119134
main_form = self.parent.parentApp.getForm("MAIN")
120135
main_form.value.load_files_and_set_values()
121136
main_form.load_files()
122137

123138
def preview_format(self):
124-
pass
139+
"""To be executed when `preview_format` option is changed"""
140+
main_form = self.parent.parentApp.getForm("MAIN")
141+
main_form.value.meta_cache = dict()
142+
main_form.value.load_preview_format()
143+
main_form.wMain.set_status(main_form.wMain.get_selected()) # change current file's preview into new format
144+

clid/main.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#!/usr/bin/env python3
22

3-
__version__ = '0.5.3'
3+
__version__ = '0.6.0'
44

5+
import os
56
import curses
7+
8+
import configobj
69
import npyscreen as npy
710

811
from . import base
@@ -11,8 +14,9 @@
1114
from . import editmeta
1215

1316

14-
class CommandLine(base.ClidCommandLine):
15-
"""Command line at the bottom.
17+
class MainActionController(base.ClidActionController):
18+
"""Object that recieves recieves inpout in command line
19+
at the bottom.
1620
1721
Note:
1822
self.parent refers to ClidInterface -> class
@@ -22,6 +26,16 @@ def create(self):
2226
super().create()
2327
self.add_action('^/.+', self.search_for_files, live=True) # search with '/'
2428

29+
def change_setting(self, command_line, widget_proxy, live):
30+
setting = command_line[5:].split(sep='=')
31+
pref_form = self.parent.parentApp.getForm("SETTINGS")
32+
pref_form.value.change_setting(setting[0], setting[1]) # writes to the ini file
33+
pref_form.value.when_changed[setting[0]]()
34+
35+
pref_form.load_pref()
36+
pref_form.wMain.display()
37+
38+
2539
def search_for_files(self, command_line, widget_proxy, live):
2640
"""Search for files while given a string"""
2741
if len(command_line[1:]) > 2: # first char will be '/'
@@ -122,18 +136,21 @@ class ClidInterface(npy.FormMuttActiveTraditional):
122136
Note:
123137
self.value refers to an instance of DATA_CONTROLER
124138
"""
125-
ACTION_CONTROLLER = CommandLine
126-
MAIN_WIDGET_CLASS = ClidMultiline
127139
DATA_CONTROLER = database.Mp3DataBase
140+
MAIN_WIDGET_CLASS = ClidMultiline
141+
ACTION_CONTROLLER = MainActionController
142+
COMMAND_WIDGET_CLASS = base.ClidCommandLine
128143

129-
def create(self):
130-
super().create() # so that status widgets are created
131-
self.set_value(self.DATA_CONTROLER()) # isn't automatically done(open issue ?)
132-
133-
# used to revert screen(ESC) to standard view after a search(see class ClidMultiline)
134-
self.after_search_now_filter_view = False
144+
def __init__(self, *args, **kwargs):
145+
super().__init__(*args, **kwargs)
146+
self.set_value(self.DATA_CONTROLER())
147+
self.value.settings = self.parentApp.settings
148+
self.value.load_files_and_set_values()
149+
self.value.load_preview_format()
135150

136151
self.load_files()
152+
153+
# widgets are created by self.create() in super()
137154
self.wStatus1.value = 'clid v' + __version__ + ' '
138155

139156
try:
@@ -142,17 +159,33 @@ def create(self):
142159
self.wStatus2.value = 'No Files Found In Directory'
143160
self.wMain.values = []
144161

162+
self.after_search_now_filter_view = False
163+
# used to revert screen(ESC) to standard view after a search(see class ClidMultiline)
164+
145165
# change to `load_pref`
146166
def load_files(self):
147167
"""Set the mp3 files that will be displayed"""
148168
self.wMain.values = self.value.get_all_values()
149169

150170

151171
class ClidApp(npy.NPSAppManaged):
152-
def onStart(self):
172+
"""Class used by npyscreen to manage forms.
173+
174+
Attributes:
175+
current_file(str):
176+
file selected when in main_view(path)
177+
settings(configobj.ConfigObj):
178+
object used to read and write preferences
179+
"""
180+
181+
def __init__(self, *args, **kwargs):
182+
super().__init__(*args, **kwargs)
153183
npy.setTheme(npy.Themes.ElegantTheme)
154184

155185
self.current_file = None # changed when a file is selected in main screen
186+
self.settings = configobj.ConfigObj(os.path.expanduser('~/.clid.ini'))
187+
188+
def onStart(self):
156189
self.addForm("MAIN", ClidInterface)
157190
self.addForm("SETTINGS", pref.PreferencesView)
158191
self.addFormClass("EDIT", editmeta.EditMeta) # addFormClass to create a new instance every time

clid/pref.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
from . import database
99

1010

11-
class PrefCommandLine(base.ClidCommandLine):
12-
def create(self):
13-
super().create()
14-
self.add_action('^:set .+', self.change_setting, live=False)
15-
11+
class PrefActionController(base.ClidActionController):
1612
def change_setting(self, command_line, widget_proxy, live):
1713
setting = command_line[5:].split(sep='=')
1814
self.parent.value.change_setting(setting[0], setting[1]) # writes to the ini file
@@ -25,7 +21,7 @@ def change_setting(self, command_line, widget_proxy, live):
2521
class PrefMultiline(npy.MultiLine):
2622
def set_up_handlers(self):
2723
super().set_up_handlers()
28-
24+
2925
self.handlers['1'] = self.switch_to_main
3026

3127
def switch_to_main(self, char):
@@ -41,17 +37,17 @@ def h_select(self, char):
4137
class PreferencesView(npy.FormMuttActiveTraditional):
4238
"""View for editing preferences/settings"""
4339
MAIN_WIDGET_CLASS = PrefMultiline
44-
ACTION_CONTROLLER = PrefCommandLine
40+
ACTION_CONTROLLER = PrefActionController
41+
COMMAND_WIDGET_CLASS = base.ClidCommandLine
4542

4643
def __init__(self, *args, **kwargs):
4744
super().__init__(*args, **kwargs)
4845
self.set_value(database.SettingsDataBase())
4946
self.value.parent = self
47+
self.value.settings = self.parentApp.settings
48+
self.value.make_strings()
5049
self.load_pref()
5150

52-
53-
def create(self):
54-
super().create()
5551
self.wStatus1.value = 'Preferences '
5652

5753
def load_pref(self):

sdf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,17 @@ multiline: <clid.database.SettingsDataBase object at 0xb6b1978c>
77
PrefCommandLine
88
<weakproxy at 0xb6af8fcc to PreferencesView at 0xb6b025cc>
99
<clid.database.SettingsDataBase object at 0xb6b1978c>
10+
multiline: <clid.database.SettingsDataBase object at 0xb6bb9a0c>
11+
multiline: <clid.database.SettingsDataBase object at 0xb6b418ec>
12+
multiline: <clid.database.SettingsDataBase object at 0xb6b10fac>
13+
multiline: <clid.database.SettingsDataBase object at 0xb6adb3ac>
14+
multiline: <clid.database.SettingsDataBase object at 0xb6b2ffac>
15+
multiline: <clid.database.SettingsDataBase object at 0xb6b2ffac>
16+
multiline: <clid.database.SettingsDataBase object at 0xb6b8dc6c>
17+
multiline: <clid.database.SettingsDataBase object at 0xb6b0304c>
18+
multiline: <clid.database.SettingsDataBase object at 0xb6bacc4c>
19+
multiline: <clid.database.SettingsDataBase object at 0xb6bacc4c>
20+
multiline: <clid.database.SettingsDataBase object at 0xb6bacc4c>
21+
multiline: <clid.database.SettingsDataBase object at 0xb6bacc6c>
22+
multiline: <clid.database.SettingsDataBase object at 0xb6bacc6c>
23+
multiline: <clid.database.SettingsDataBase object at 0xb6becd4c>

0 commit comments

Comments
 (0)