import base64 from . import pyproto def proto(d, padding=False): return base64.urlsafe_b64encode(pyproto.ProtoBuf(d).toBuf()) \ .decode('ascii').replace("=", "%3D" if padding else "") def continuation(subject, params, query=None): return proto({ 80226972: { 2: subject, 3: proto(params, padding=True), 11: query, } }, padding=True) def make_sp(sort=None, date=None, type=None, len=None, features=[], extras=[]): sortorder = dict(relevance=0, rating=1, date=2, views=3) datefilter = dict(hour=1, day=2, week=3, month=4, year=5) typefilter = dict(video=1, channel=2, playlist=3, movie=4, show=5) lenfilter = dict(short=1, long=2, medium=3) # short=0-4min, long=20+min, medium=4-20min extraflags = dict(verbatim=1) featureflags = dict(is_hd=4, subtitles=5, ccommons=6, is_3d=7, live=8, purchased=9, is_4k=14, is_360=15, location=23, is_hdr=25) return proto({ 1: sortorder.get(sort), 2: { 1: datefilter.get(date), 2: typefilter.get(type), 3: lenfilter.get(len), **{featureflags[k]:True for k in features if k in featureflags} } if date or type or len or features else None, 8: { extraflags[k]:True for k in extras if k in extraflags } or None }, padding=True) def make_channel_params(subject, typ="videos", sort=None, query=None): if typ in ("playlists",): sortorder = dict(newest=3, modified=4) return continuation(subject, { 2: "playlists", #type_s 4: 1, #type_i 3: sortorder.get(sort),#sort optional 7: 1, #unknown_const1 23: 0, #unknown_const2 6: 2, #list_or_grid (2=list, None/1=grid) 61: proto({1: proto({1: 0})}) #offset }) elif typ in ("search",): return continuation(subject, { 2: "search",#type_s 7: 1, #unknown_const1 23: 0, #unknown_const2 6: 2, #list_or_grid (2=list, None/1=grid) }, query) elif typ in ("videos", "streams", "shorts"): sortorder = dict(newest=1, popular=2) typekey = dict(videos=15, streams=14, shorts=10) return continuation(subject, { 110: { 3: { typekey[typ]: { 2: { 1: "00000000-0000-0000-0000-000000000000" }, 3: sortorder.get(sort,1) } }}}) else: raise NotImplementedError def make_playlist_params(playlist_id, offset): # mix takes video id instead of offset. an id not in the playlist requests the beginning. mix_playlist = playlist_id.startswith("RD") return continuation("VL" + playlist_id, { 15: "PT:" + proto( { 2: '___________' } if mix_playlist else { 1: offset } ) })