else:
filter_parts.append(string)
- def _parse_format_selection(tokens, endwith=[]):
+ def _parse_format_selection(tokens, inside_merge=False, inside_choice=False, inside_group=False):
selectors = []
current_selector = None
for type, string, start, _, _ in tokens:
elif type in [tokenize.NAME, tokenize.NUMBER]:
current_selector = FormatSelector(SINGLE, string, [])
elif type == tokenize.OP:
- if string in endwith:
+ if string == ')':
+ if not inside_group:
+ # ')' will be handled by the parentheses group
+ tokens.restore_last_token()
break
- elif string == ')':
- # ')' will be handled by the parentheses group
+ elif inside_merge and string in ['/', ',']:
tokens.restore_last_token()
break
- if string == ',':
+ elif inside_choice and string == ',':
+ tokens.restore_last_token()
+ break
+ elif string == ',':
+ if not current_selector:
+ raise syntax_error('"," must follow a format selector', start)
selectors.append(current_selector)
current_selector = None
elif string == '/':
first_choice = current_selector
- second_choice = _parse_format_selection(tokens, [','])
- current_selector = None
- selectors.append(FormatSelector(PICKFIRST, (first_choice, second_choice), []))
+ second_choice = _parse_format_selection(tokens, inside_choice=True)
+ current_selector = FormatSelector(PICKFIRST, (first_choice, second_choice), [])
elif string == '[':
if not current_selector:
current_selector = FormatSelector(SINGLE, 'best', [])
elif string == '(':
if current_selector:
raise syntax_error('Unexpected "("', start)
- current_selector = FormatSelector(GROUP, _parse_format_selection(tokens, [')']), [])
+ group = _parse_format_selection(tokens, inside_group=True)
+ current_selector = FormatSelector(GROUP, group, [])
elif string == '+':
video_selector = current_selector
- audio_selector = _parse_format_selection(tokens, [','])
- current_selector = None
- selectors.append(FormatSelector(MERGE, (video_selector, audio_selector), []))
+ audio_selector = _parse_format_selection(tokens, inside_merge=True)
+ if not video_selector or not audio_selector:
+ raise syntax_error('"+" must be between two format selectors', start)
+ current_selector = FormatSelector(MERGE, (video_selector, audio_selector), [])
else:
raise syntax_error('Operator not recognized: "{0}"'.format(string), start)
elif type == tokenize.ENDMARKER:
format_spec = selector.selector
def selector_function(formats):
+ formats = list(formats)
+ if not formats:
+ return
if format_spec == 'all':
for f in formats:
yield f