diff --git a/README.md b/README.md index d3e950869..45d4c29ca 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,9 @@ which means you can modify it, redistribute it or use it however you like. be evaluated. For example, the youtube playlist 'Liked videos' will not be downloaded with the following filter : - --match-filter "playlist_title != Liked videos" + --match-filter "playlist_title != Liked videos". + Most valid characters for a valid youtube + playlist name in English can also be used. --no-playlist Download only the video, if the URL refers to a video and a playlist. --yes-playlist Download the playlist, if the URL refers to diff --git a/test/test_utils.py b/test/test_utils.py index 5e0754fe1..22597f415 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -715,6 +715,21 @@ ffmpeg version 2.4.4 Copyright (c) 2000-2014 the FFmpeg ...'''), '2.4.4') self.assertFalse(match_str( 'playlist_title != some playlist with space & playlist_title != foobar', {'playlist_title': 'some playlist with space'})) + self.assertFalse(match_str( + 'playlist_title != some playlist with space & playlist_title != foobar', + {'playlist_title': ' some playlist with space '})) + self.assertTrue(match_str( + 'playlist_title != some playlist with space & playlist_title != foobar', + {'playlist_title': ' some playlist with space but other name '})) + self.assertTrue(match_str( + "playlist_title = It's a playlist with quote", + {'playlist_title': "It's a playlist with quote"})) + self.assertTrue(match_str( + "playlist_title = playlist with {}[]/\()", + {'playlist_title': "playlist with {}[]/\()"})) + self.assertTrue(match_str( + "playlist_title = playlist with valid characters +~#^!?§:;.", + {'playlist_title': "playlist with valid characters +~#^!?§:;."})) def test_parse_dfxp_time_expr(self): self.assertEqual(parse_dfxp_time_expr(None), None) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 128248a52..517c4aee1 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -1962,7 +1962,7 @@ def _match_one(filter_part, dct): \s*(?P%s)(?P\s*\?)?\s* (?: (?P[0-9.]+(?:[kKmMgGtTpPeEzZyY]i?[Bb]?)?)| - (?P(?![0-9.])[a-z0-9A-Z\s_-]*) + (?P(?![0-9.])[a-z0-9A-Z\.\'\(\)\{\}\[\]/\\\^\?:;~#!§+\s_-]*) ) \s*$ ''' % '|'.join(map(re.escape, COMPARISON_OPERATORS.keys()))) @@ -1973,7 +1973,7 @@ def _match_one(filter_part, dct): if m.group('op') not in ('=', '!='): raise ValueError( 'Operator %s does not support string values!' % m.group('op')) - comparison_value = m.group('strval') + comparison_value = m.group('strval').strip() else: try: comparison_value = int(m.group('intval')) @@ -1988,6 +1988,8 @@ def _match_one(filter_part, dct): actual_value = dct.get(m.group('key')) if actual_value is None: return m.group('none_inclusive') + if isinstance(actual_value, compat_basestring): + actual_value = actual_value.strip() return op(actual_value, comparison_value) UNARY_OPERATORS = { @@ -2011,7 +2013,7 @@ def match_str(filter_str, dct): """ Filter a dictionary with a simple string syntax. Returns True (=passes filter) or false """ return all( - _match_one(filter_part.strip(), dct) for filter_part in filter_str.split('&')) + _match_one(filter_part, dct) for filter_part in filter_str.split('&')) def match_filter_func(filter_str):