cplay-ng

simple curses audio player
git clone https://git.ce9e.org/cplay-ng.git

commit
1ffce1d9b05e4b197005d7db0daaedfb907c791f
parent
a80673647541c0f79597417e6ce629050a3bdd19
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2026-04-25 07:48
improve symlink handling

- include symlink dirs in directory listings
- ignore loops when adding a directory

Diffstat

M cplay.py 62 ++++++++++++++++++++++++++++++++-----------------------------

1 files changed, 33 insertions, 29 deletions


diff --git a/cplay.py b/cplay.py

@@ -108,7 +108,7 @@ def relpath(path):
  108   108     if path.startswith('http'):
  109   109         return path
  110   110     else:
  111    -1         return os.path.relpath(path)
   -1   111         return os.path.relpath(path, filelist.path)
  112   112 
  113   113 
  114   114 @contextmanager
@@ -132,16 +132,34 @@ def listdir(path):
  132   132     try:
  133   133         with os.scandir(path) as it:
  134   134             for entry in sorted(it, key=lambda e: e.name):
  135    -1                 if entry.name[0] != '.':
  136    -1                     yield (
  137    -1                         entry.path,
  138    -1                         get_ext(entry.name),
  139    -1                         entry.is_dir(follow_symlinks=False),
  140    -1                     )
   -1   135                 if entry.name.startswith('.'):
   -1   136                     continue
   -1   137                 ext = get_ext(entry.name)
   -1   138                 if entry.is_dir() or ext in AUDIO_EXTENSIONS or ext == 'm3u':
   -1   139                     yield entry
  141   140     except OSError:
  142   141         pass
  143   142 
  144   143 
   -1   144 def walk(path, seen=None):
   -1   145     realpath = os.path.realpath(path)
   -1   146     seen = seen or set()
   -1   147     if realpath in seen:
   -1   148         return []
   -1   149     seen.add(realpath)
   -1   150 
   -1   151     result = []
   -1   152     for entry in listdir(path):
   -1   153         if entry.is_dir():
   -1   154             children = walk(entry.path, seen)
   -1   155             if children:
   -1   156                 result.append(entry.path)
   -1   157                 result += children
   -1   158         else:
   -1   159             result.append(entry.path)
   -1   160     return result
   -1   161 
   -1   162 
  145   163 class Player:
  146   164     def __init__(self):
  147   165         self.path = None
@@ -443,10 +461,7 @@ class Filelist(List):
  443   461         self.all_items = []
  444   462         self.rsearch_str = ''
  445   463 
  446    -1         for p, ext, is_dir in listdir(path):
  447    -1             if is_dir or ext == 'm3u' or ext in AUDIO_EXTENSIONS:
  448    -1                 self.all_items.append(p)
  449    -1 
   -1   464         self.all_items = [entry.path for entry in listdir(path)]
  450   465         self.items = self.all_items
  451   466 
  452   467         if prev and prev in self.items:
@@ -455,21 +470,9 @@ class Filelist(List):
  455   470             self.position = 0
  456   471             self.cursor = 0
  457   472 
  458    -1     def build_search_cache(self, root):
  459    -1         results = []
  460    -1         for path, ext, is_dir in listdir(root):
  461    -1             if is_dir:
  462    -1                 children = self.build_search_cache(path)
  463    -1                 if children:
  464    -1                     results.append(path)
  465    -1                     results += children
  466    -1             elif ext in AUDIO_EXTENSIONS or ext == 'm3u':
  467    -1                 results.append(path)
  468    -1         return results
  469    -1 
  470   473     def filter(self, query):
  471   474         if not self.search_cache:
  472    -1             self.search_cache = self.build_search_cache(self.path)
   -1   475             self.search_cache = walk(self.path)
  473   476 
  474   477         if query:
  475   478             if self.rsearch_str and query.startswith(self.rsearch_str):
@@ -618,10 +621,11 @@ class Playlist(List):
  618   621         except IndexError:
  619   622             self.active = -1
  620   623 
  621    -1     def add_dir(self, path):
   -1   624     def add_dir(self, root):
  622   625         count = 0
  623    -1         for p, _ext, _is_dir in listdir(path):
  624    -1             count += self.add(p, recursive=True)
   -1   626         for path in walk(root):
   -1   627             if get_ext(path) in AUDIO_EXTENSIONS:
   -1   628                 count += self.add(path)
  625   629         return count
  626   630 
  627   631     def add_playlist(self, path):
@@ -638,11 +642,11 @@ class Playlist(List):
  638   642                 count += 1
  639   643         return count
  640   644 
  641    -1     def add(self, path, *, recursive=False):
   -1   645     def add(self, path):
  642   646         ext = get_ext(path)
  643   647         if os.path.isdir(path):
  644   648             return self.add_dir(path)
  645    -1         elif ext == 'm3u' and not recursive:
   -1   649         elif ext == 'm3u':
  646   650             return self.add_playlist(path)
  647   651         elif ext in AUDIO_EXTENSIONS:
  648   652             self.items.append(path)