func (mf *MediaFilters) normalizeBitrateFilter() {
	if mf.Bitrate == nil {
		return
	}
	if mf.Audios.Bitrate == nil {
		mf.Audios.Bitrate = mf.Bitrate
	}
	if mf.Videos.Bitrate == nil {
		mf.Videos.Bitrate = mf.Bitrate
	}
	mf.Bitrate = nil
}
normalizeBitrateFilter will finalize the nested bitrate filter by comparing it to
overall bitrate filter and overriding any necessary values
package parsers
import (
	"fmt"
	"math"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"
)
type MediaFilters struct {
	Videos                 NestedFilters `json:",omitempty"`
	Audios                 NestedFilters `json:",omitempty"`
	Captions               NestedFilters `json:",omitempty"`
	ContentTypes           []string      `json:",omitempty"`
	Plugins                []string      `json:",omitempty"`
	Tags                   *Tags         `json:",omitempty"`
	Trim                   *Trim         `json:",omitempty"`
	Bitrate                *Bitrate      `json:",omitempty"`
	FrameRate              []string      `json:",omitempty"`
	DeWeave                bool          `json:",omitempty"`
	PreventHTTPStatusError bool          `json:",omitempty"`
	Protocol               Protocol      `json:"protocol"`
}
type NestedFilters struct {
	Bitrate  *Bitrate `json:",omitempty"`
	Codecs   []string `json:",omitempty"`
	Language []string `json:",omitempty"`
}
type Protocol string
const (
	ProtocolHLS Protocol = "hls"
	ProtocolDASH Protocol = "dash"
	ProtocolVTT Protocol = "vtt"
)
type Trim struct {
	Start int `json:",omitempty"`
	End   int `json:",omitempty"`
}
type Bitrate struct {
	Max int `json:",omitempty"`
	Min int `json:",omitempty"`
}
type Tags struct {
	Ads    bool `json:",omitempty"`
	IFrame bool `json:",omitempty"`
}
var urlParseRegexp = regexp.MustCompile(`(.*?)\((.*)\)`)
var nestedFilterRegexp = regexp.MustCompile(`\),`)
var codecSupported = map[string]struct{}{
	"hdr10": struct{}{},  
	"dvh":   struct{}{},  
	"hevc":  struct{}{},  
	"hvc":   struct{}{},  
	"avc":   struct{}{},  
	"av1":   struct{}{},  
	"mp4a":  struct{}{},  
	"ac-3":  struct{}{},  
	"ec-3":  struct{}{},  
	"stpp":  struct{}{},  
	"wvtt":  struct{}{},  
}
var contentSupported = map[string]struct{}{
	"image": struct{}{},
	"text":  struct{}{},
	"audio": struct{}{},
	"video": struct{}{},
}
func keyError(key string, e error) (string, *MediaFilters, error) {
	return "", &MediaFilters{}, fmt.Errorf("%v: %w", key, e)
}
func URLParse(urlpath string) (string, *MediaFilters, error) {
	mf := new(MediaFilters)
	parts := strings.Split(urlpath, "/")
	re := urlParseRegexp
	masterManifestPath := "/"
	if strings.Contains(urlpath, ".m3u8") {
		mf.Protocol = ProtocolHLS
	} else if strings.Contains(urlpath, ".mpd") {
		mf.Protocol = ProtocolDASH
	} else if strings.Contains(urlpath, ".vtt") {
		mf.Protocol = ProtocolVTT
	} else {
		return keyError("Protocol", fmt.Errorf("unsupported protocol"))
	}
	for _, part := range parts {
		subparts := re.FindStringSubmatch(part)
		if len(subparts) != 3 {
			if mf.parsePlugins(part) {
				continue
			}
			masterManifestPath = path.Join(masterManifestPath, part)
			continue
		}
		filters := strings.Split(subparts[2], ",")
		nestedFilterRegexp := regexp.MustCompile(`\),`)
		nestedFilters := splitAfter(subparts[2], nestedFilterRegexp)
		switch key := subparts[1]; key {
		case "v":
			for _, nf := range nestedFilters {
				if err := mf.Videos.parse(nf); err != nil {
					return keyError("Video", err)
				}
			}
		case "a":
			for _, nf := range nestedFilters {
				if err := mf.Audios.parse(nf); err != nil {
					return keyError("Audio", err)
				}
			}
		case "c":
			for _, nf := range nestedFilters {
				if err := mf.Captions.parse(nf); err != nil {
					return keyError("Captions", err)
				}
			}
		case "ct":
			for _, contentType := range filters {
				if _, valid := contentSupported[contentType]; !valid {
					err := fmt.Errorf("Content Type %v is not supported", contentType)
					return keyError("Content Type", err)
				}
				mf.ContentTypes = append(mf.ContentTypes, contentType)
			}
		case "l":
			for _, lang := range filters {
				mf.Audios.Language = append(mf.Audios.Language, lang)
				mf.Captions.Language = append(mf.Captions.Language, lang)
			}
		case "b":
			x, y, err := parseAndValidateInts(filters, math.MaxInt32)
			if err != nil {
				return keyError("Bitrate", err)
			}
			mf.Bitrate = &Bitrate{
				Min: x,
				Max: y,
			}
		case "t":
			x, y, err := parseAndValidateInts(filters, int(time.Now().Unix()))
			if err != nil {
				return keyError("Trim", err)
			}
			mf.Trim = &Trim{
				Start: x,
				End:   y,
			}
		case "tags":  
			mf.Tags = &Tags{}
			mf.Tags.parse(filters)
		case "fps":  
			for _, framerate := range filters {
				fr := strings.ReplaceAll(framerate, ":", "/")
				mf.FrameRate = append(mf.FrameRate, fr)
			}
		case "dw":
			if len(filters) > 1 {
				return keyError("DeWeave", fmt.Errorf("Only accepts one boolean value"))
			}
			w, err := parseAndValidateBooleanString(filters[0])
			if err != nil {
				return keyError("DeWeave", err)
			}
			mf.DeWeave = w
		case "phe":
			if len(filters) > 1 {
				return keyError("PreventHTTPStatusError", fmt.Errorf("Only accepts one boolean value"))
			}
			f, err := parseAndValidateBooleanString(filters[0])
			if err != nil {
				return keyError("PreventHTTPStatusError", err)
			}
			mf.PreventHTTPStatusError = f
		}
	}
	mf.normalizeBitrateFilter()
	return masterManifestPath, mf, nil
}
func (mf *MediaFilters) parsePlugins(path string) bool {
	re := regexp.MustCompile(`\[(.*)\]`)
	subparts := re.FindStringSubmatch(path)
	if len(subparts) == 2 {
		for _, plugin := range strings.Split(subparts[1], ",") {
			mf.Plugins = append(mf.Plugins, plugin)
		}
		return true
	}
	return false
}
func (nf *NestedFilters) parse(nestedFilter string) error {
	splitNestedFilter := urlParseRegexp.FindStringSubmatch(nestedFilter)
	var key string
	var param []string
	if len(splitNestedFilter) == 0 {  
		key = "co"
		param = strings.Split(nestedFilter, ",")
	} else {
		key = splitNestedFilter[1]
		param = strings.Split(splitNestedFilter[2], ",")
	}
	splitKey := strings.Split(key, ",")
	if len(splitKey) == 1 {
		return nf.parseKeys(key, param)
	}
	var keys []string
	var params [][]string
	for i, part := range splitKey {
		if i == len(splitKey)-1 {
			keys = append(keys, part)
			params = append(params, param)
		} else {
			keys = append(keys, "co")
			params = append(params, []string{part})
		}
	}
	for i := range keys {
		err := nf.parseKeys(keys[i], params[i])
		if err != nil {
			return err
		}
	}
	return nil
}
func (nf *NestedFilters) parseKeys(key string, values []string) error {
	switch key {
	case "co":
		for _, v := range values {
			switch v {
			case "hdr10":
				nf.Codecs = append(nf.Codecs, "hev1.2", "hvc1.2")
			default:
				if _, valid := codecSupported[v]; !valid {
					return fmt.Errorf("Codec %v is not supported", v)
				}
				nf.Codecs = append(nf.Codecs, v)
			}
		}
	case "l":
		for _, v := range values {
			nf.Language = append(nf.Language, v)
		}
	case "b":
		x, y, err := parseAndValidateInts(values, math.MaxInt32)
		if err != nil {
			return err
		}
		nf.Bitrate = &Bitrate{
			Min: x,
			Max: y,
		}
	}
	return nil
}