]>
git.gir.st - subscriptionfeed.git/blob - app/browse/protobuf.py
4 from dataclasses
import dataclass
5 from typing
import Optional
7 from pure_protobuf
.dataclasses_
import field
, message
8 from pure_protobuf
.types
import int64
10 def b64e(b
, padding
=True):
11 return base64
.urlsafe_b64encode(b
).decode('ascii') \
12 .replace("=", "%3D" if padding
else "")
14 def proto(d
, padding
=False):
15 return base64
.urlsafe_b64encode(pyproto
.ProtoBuf(d
).toBuf()) \
16 .decode('ascii').replace("=", "%3D" if padding
else "")
18 def continuation(subject
, params
, query
=None):
22 3: proto(params
, padding
=True),
31 verbatim
: Optional
[bool] = field(1, default
=None) # don't fix spelling
34 class Filters
: # adapted from invidious
35 date
: Optional
[int64
] = field(1, default
=None)
36 type: Optional
[int64
] = field(2, default
=None)
37 length
: Optional
[int64
] = field(3, default
=None)
38 is_hd
: Optional
[bool] = field(4, default
=None)
39 subtitles
: Optional
[bool] = field(5, default
=None)
40 ccommons
: Optional
[bool] = field(6, default
=None)
41 is_3d
: Optional
[bool] = field(7, default
=None)
42 live
: Optional
[bool] = field(8, default
=None)
43 purchased
: Optional
[bool] = field(9, default
=None)
44 is_4k
: Optional
[bool] = field(14, default
=None)
45 is_360
: Optional
[bool] = field(15, default
=None)
46 location
: Optional
[bool] = field(23, default
=None)
47 is_hdr
: Optional
[bool] = field(25, default
=None)
51 sorted: Optional
[int64
] = field(1, default
=None)
52 filter: Optional
[Filters
] = field(2, default
=None)
53 extras
: Optional
[Extras
] = field(8, default
=None)
55 def make_sp(sort
=None, date
=None, type=None, len=None, features
=[], extras
=[]):
56 sortorder
= dict(relevance
=0, rating
=1, date
=2, views
=3)
57 datefilter
= dict(hour
=1, day
=2, week
=3, month
=4, year
=5)
58 typefilter
= dict(video
=1, channel
=2, playlist
=3, movie
=4, show
=5)
59 lenfilter
= dict(short
=1, long=2)
61 return b64e(SearchRequest(
62 sorted=sortorder
.get(sort
),
64 date
=datefilter
.get(date
),
65 type=typefilter
.get(type),
66 length
=lenfilter
.get(len),
67 **{f
:True for f
in features
},
68 ) if date
or type or len or features
else None,
69 extras
=Extras(**{f
:True for f
in extras
}),
74 def make_channel_params(subject
, typ
="videos", sort
=None, query
=None):
75 if typ
in ("playlists",):
76 sortorder
= dict(newest
=3, modified
=4)
77 return continuation(subject
, {
78 2: "playlists", #type_s
80 3: sortorder
.get(sort
),#sort optional
82 23: 0, #unknown_const2
83 6: 2, #list_or_grid (2=list, None/1=grid)
84 61: proto({1: proto({1: 0})}) #offset
86 elif typ
in ("search",):
87 return continuation(subject
, {
90 23: 0, #unknown_const2
91 6: 2, #list_or_grid (2=list, None/1=grid)
93 elif typ
in ("videos", "streams", "shorts"):
94 sortorder
= dict(newest
=1, popular
=2)
95 typekey
= dict(videos
=15, streams
=14, shorts
=10)
96 return continuation(subject
, { 110: { 3: {
98 2: { 1: "00000000-0000-0000-0000-000000000000" },
99 3: sortorder
.get(sort
,1)
103 raise NotImplementedError
107 def make_playlist_params(playlist_id
, offset
):
108 # mix takes video id instead of offset. an id not in the playlist requests the beginning.
109 mix_playlist
= playlist_id
.startswith("RD")
110 return continuation("VL" + playlist_id
, {
112 { 2: '___________' } if mix_playlist
else { 1: offset
}