mirror of
https://github.com/beetbox/beets.git
synced 2025-12-15 21:14:19 +01:00
path encoding now works with slashes better
--HG-- extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%40199
This commit is contained in:
parent
597694b58b
commit
0b309edd27
2 changed files with 97 additions and 24 deletions
|
|
@ -140,35 +140,27 @@ def seq_to_path(seq):
|
|||
"""
|
||||
out = []
|
||||
for s in seq:
|
||||
out.append(s.replace('\\', '\\\\').replace('/', '\\/'))
|
||||
out.append(s.replace('\\', '\\\\') # preserve backslashes
|
||||
.replace('_', '\\_') # preserve _s
|
||||
.replace('/', '_') # hide /s as _s
|
||||
)
|
||||
return '/'.join(out)
|
||||
|
||||
path_to_list_pattern = re.compile(r'(?:\\/|[^/])*')
|
||||
|
||||
def path_to_list(path):
|
||||
"""Takes a path-like string (probably encoded by seq_to_path) and
|
||||
returns the list of strings it represents.
|
||||
"""
|
||||
# To simplify parsing, ensure that everything is terminated by a
|
||||
# slash. Note that seq_to_path never added a trailing slash, so
|
||||
# they are "disallowed" by this encoding.
|
||||
path += '/'
|
||||
|
||||
out = []
|
||||
while path:
|
||||
|
||||
# Search for one path component.
|
||||
m = path_to_list_pattern.match(path)
|
||||
if not m: break # Should never happen.
|
||||
component = m.group(0)
|
||||
|
||||
# Chop off this component and the / that follows it.
|
||||
path = path[len(component):]
|
||||
if len(path) >= 1 and path[0] == '/': # Should always be true.
|
||||
path = path[1:]
|
||||
|
||||
out.append(component.replace('\\/', '/').replace('\\\\', '\\'))
|
||||
|
||||
return out
|
||||
def repl(m):
|
||||
# This function maps "escaped" characters to original
|
||||
# characters. Because the regex is in the right order, the
|
||||
# sequences are replaced top-to-bottom.
|
||||
return {'\\\\': '\\',
|
||||
'\\_': '_',
|
||||
'_': '/',
|
||||
}[m.group(0)]
|
||||
return [re.sub(r'\\\\|\\_|_', repl, component)
|
||||
for component in path.split('/')]
|
||||
|
||||
|
||||
# Generic server infrastructure, implementing the basic protocol.
|
||||
|
|
@ -792,7 +784,7 @@ class Server(BaseServer):
|
|||
|
||||
if not artist: # List all artists.
|
||||
for artist in self.lib.artists():
|
||||
conn.send('directory: ' + artist)
|
||||
conn.send('directory: ' + seq_to_path((artist,)))
|
||||
elif not album: # List all albums for an artist.
|
||||
for album in self.lib.albums(artist):
|
||||
conn.send('directory: ' + seq_to_path(album))
|
||||
|
|
|
|||
81
test/test_player.py
Normal file
81
test/test_player.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# This file is part of beets.
|
||||
# Copyright 2009, Adrian Sampson.
|
||||
#
|
||||
# Beets is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Beets is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with beets. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Tests for BPD and music playing.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from beets.player import bpd
|
||||
|
||||
class FauxPathTest(unittest.TestCase):
|
||||
|
||||
# The current encoding actually cannot distinguish between ['']
|
||||
# and []. This doesn't cause a bug because we never use empty
|
||||
# sequences, but it might be nice to fix someday.
|
||||
#def test_empty_seq_preserved(self):
|
||||
# seq = []
|
||||
# self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_single_element_preserved(self):
|
||||
seq = ['hello']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_multiple_elements_preserved(self):
|
||||
seq = ['hello', 'there', 'how', 'are', 'you']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_spaces_preserved(self):
|
||||
seq = ['hel lo', 'what', 'is up']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_empty_string_preserved_in_middle(self):
|
||||
seq = ['hello', '', 'sup']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_empty_strings_preserved_on_ends(self):
|
||||
seq = ['', 'whatever', '']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_empty_strings_only(self):
|
||||
seq = ['', '', '']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_slashes_preserved(self):
|
||||
seq = ['hel/lo', 'what', 'is', 'up']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_backslashes_preserved(self):
|
||||
seq = ['hel\\lo', 'what', 'is', 'up']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_unicode_preserved(self):
|
||||
seq = [u'hello', u'what \x99 is', u'up']
|
||||
self.assertEqual(bpd.path_to_list(bpd.seq_to_path(seq)), seq)
|
||||
|
||||
def test_slashes_not_encoded_as_slashes(self):
|
||||
no_slashes = bpd.seq_to_path(['goodday', 'sir'])
|
||||
with_slashes = bpd.seq_to_path(['good/day', 'sir'])
|
||||
self.assertEqual(no_slashes.count('/'), with_slashes.count('/'))
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
Loading…
Reference in a new issue