Skip to content

Commit

Permalink
Add visitor data
Browse files Browse the repository at this point in the history
  • Loading branch information
iBicha committed Jan 18, 2025
1 parent 6f74ee6 commit 9470860
Show file tree
Hide file tree
Showing 26 changed files with 162 additions and 15 deletions.
1 change: 1 addition & 0 deletions playlet-lib/src/components/MainScene.transpiled.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<SearchHistory id="SearchHistory" />
<ProfilesService id="ProfilesService" />
<Invidious id="Invidious" />
<Innertube id="Innertube" />
<PlayletWebServer id="WebServer" port="8888" />
<DialServer id="DialServer" />
<LoungeService id="LoungeService" />
Expand Down
3 changes: 3 additions & 0 deletions playlet-lib/src/components/MainScene.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<VideoQueue id="VideoQueue"
appController="bind:/AppController"
videoContainer="bind:../VideoContainer"
innertube="bind:../Innertube"
invidious="bind:../Invidious"
notifications="bind:../Notifications"
preferences="bind:../Preferences"
Expand All @@ -77,10 +78,12 @@
profilesService="bind:../ProfilesService" />

<!-- Tasks -->
<Innertube id="Innertube" />
<PlayletWebServer id="WebServer"
port="8888"
appController="bind:/AppController"
applicationInfo="bind:../ApplicationInfo"
innertube="bind:../Innertube"
invidious="bind:../Invidious"
profilesService="bind:../ProfilesService"
preferences="bind:../Preferences"
Expand Down
2 changes: 2 additions & 0 deletions playlet-lib/src/components/MainScene_bindings.transpiled.brs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function InitializeBindings()
"VideoQueue": {
"appController": "/AppController",
"videoContainer": "../VideoContainer",
"innertube": "../Innertube",
"invidious": "../Invidious",
"notifications": "../Notifications",
"preferences": "../Preferences",
Expand All @@ -38,6 +39,7 @@ function InitializeBindings()
"WebServer": {
"appController": "/AppController",
"applicationInfo": "../ApplicationInfo",
"innertube": "../Innertube",
"invidious": "../Invidious",
"profilesService": "../ProfilesService",
"preferences": "../Preferences",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Innertube
deviceInfo = CreateObject("roDeviceInfo")

payload = {
"context": Innertube.CreateContext(clienType, deviceInfo, "")
"context": Innertube.CreateContext(clienType, deviceInfo, "", "")
}

if not StringUtils.IsNullOrEmpty(continuation)
Expand Down
8 changes: 5 additions & 3 deletions playlet-lib/src/components/Services/Innertube/Context.bs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace Innertube
end if
end function

function CreateContext(clienType as Innertube.ClientType, deviceInfo as object, ctt as string) as object
function CreateContext(clienType as Innertube.ClientType, deviceInfo as object, ctt as string, visitorData as string) as object
client = invalid
if clienType = ClientType.Web
client = CreateContextClientWeb(deviceInfo)
Expand Down Expand Up @@ -64,6 +64,10 @@ namespace Innertube
}]
end if

if not StringUtils.IsNullOrEmpty(visitorData)
context["client"]["visitorData"] = visitorData
end if

return context
end function

Expand All @@ -76,7 +80,6 @@ namespace Innertube
"screenHeightPoints": 1440
"screenPixelDensity": 1
"screenWidthPoints": 2560
"visitorData": ""
"clientName": "WEB"
"clientVersion": INNERTUBE_WEB_CLIENT_VERSION
"osName": "Windows"
Expand Down Expand Up @@ -110,7 +113,6 @@ namespace Innertube
"screenHeightPoints": 1440
"screenPixelDensity": 1
"screenWidthPoints": 2560
"visitorData": ""
"clientName": "iOS"
"clientVersion": INNERTUBE_IOS_CLIENT_VERSION
"osName": "iOS"
Expand Down
9 changes: 9 additions & 0 deletions playlet-lib/src/components/Services/Innertube/Innertube.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import "pkg:/components/Services/Innertube/Constants.bs"
import "pkg:/source/AsyncTask/AsyncTask.bs"
import "pkg:/source/AsyncTask/Tasks.bs"

function Init()
AsyncTask.Start(Tasks.InnertubeInitTask, {
innertube: m.top
})
end function
5 changes: 5 additions & 0 deletions playlet-lib/src/components/Services/Innertube/Innertube.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<component name="Innertube" extends="Node">
<interface>
<field id="visitorData" type="string" />
</interface>
</component>
15 changes: 15 additions & 0 deletions playlet-lib/src/components/Services/Innertube/InnertubeInitTask.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import "pkg:/components/Services/Innertube/SessionData.bs"

@asynctask
function InnertubeInitTask(input as object) as object
innertubeNode = input.innertube

sessionData = Innertube.GetSessionData()
if sessionData = invalid
return invalid
end if

innertubeNode.visitorData = sessionData.visitorData

return invalid
end function
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace InnertubeService
cancellation = invalid
fetchNext = true
ctt = ""
visitorData = ""
raw = false

if options <> invalid
Expand All @@ -33,9 +34,12 @@ namespace InnertubeService
if options.DoesExist("raw")
raw = options.raw
end if
if options.DoesExist("visitorData")
visitorData = options.visitorData
end if
end if

playerRequest = Innertube.CreatePlayerRequest(videoId, ctt)
playerRequest = Innertube.CreatePlayerRequest(videoId, ctt, visitorData)
playerRequest.Cancellation(cancellation)
playerRequest.Send()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Innertube
deviceInfo = CreateObject("roDeviceInfo")

payload = {
"context": Innertube.CreateContext(Innertube.ClientType.Web, deviceInfo, ctt)
"context": Innertube.CreateContext(Innertube.ClientType.Web, deviceInfo, ctt, "")
}
payload.Append(payloadArgs)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import "pkg:/source/utils/Types.bs"

namespace Innertube

function CreatePlayerRequest(videoId as string, ctt as string) as object
function CreatePlayerRequest(videoId as string, ctt as string, visitorData as string) as object
deviceInfo = CreateObject("roDeviceInfo")

payload = {
"videoId": videoId
"context": Innertube.CreateContext(Innertube.ClientType.IOS, deviceInfo, ctt)
"context": Innertube.CreateContext(Innertube.ClientType.IOS, deviceInfo, ctt, visitorData)
"playbackContext": {
"contentPlaybackContext": {
"vis": 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Innertube
deviceInfo = CreateObject("roDeviceInfo")

payload = {
"context": CreateContext(ClientType.Web, deviceInfo, "")
"context": CreateContext(ClientType.Web, deviceInfo, "", "")
"url": url
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Innertube
deviceInfo = CreateObject("roDeviceInfo")

payload = {
context: Innertube.CreateContext(Innertube.ClientType.WEB, deviceInfo, "")
context: Innertube.CreateContext(Innertube.ClientType.WEB, deviceInfo, "", "")
}

if continuation <> ""
Expand Down
91 changes: 91 additions & 0 deletions playlet-lib/src/components/Services/Innertube/SessionData.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import "pkg:/components/Services/Innertube/Constants.bs"
import "pkg:/source/services/HttpClient.bs"
import "pkg:/source/utils/Logging.bs"
import "pkg:/source/utils/ObjectUtils.bs"
import "pkg:/source/utils/RegistryUtils.bs"
import "pkg:/source/utils/StringUtils.bs"
import "pkg:/source/utils/TimeUtils.bs"

namespace Innertube

const SESSION_DATA_VERSION = 1
const INNERTUBE_VISITOR_DATA_LIFESPAN = 1000 * 60 * 60 * 24

function GetSessionData() as object
sessionData = ReadSessionDataFromRegistry()
if sessionData <> invalid
return sessionData
end if

sessionData = RequestSessionData()
if sessionData = invalid
return invalid
end if

RegistryUtils.Write(RegistryUtils.INNERTUBE_SESSION_DATA, FormatJson(sessionData))
return sessionData
end function

function RequestSessionData() as object
request = HttpClient.Get("https://www.youtube.com/sw.js_data")
request.Headers({
"Accept-Language": "en-US,en;q=0.9"
"User-Agent": INNERTUBE_WEB_USER_AGENT
"Accept": "*/*"
"Referer": "https://www.youtube.com/sw.js"
})

response = request.Await()
if not response.IsSuccess()
LogError("Failed to fetch session data", response.ErrorMessage())
return invalid
end if

text = ValidString(response.Text())
if not text.StartsWith(")]}'")
LogError("Invalid session data response", text)
return invalid
end if

text = text.Replace(")]}'", "")
json = ParseJson(text)
if json = invalid
LogError("Failed to parse session data", text)
return invalid
end if

visitorData = ObjectUtils.Dig(json, [0, 2, 0, 0, 13])
if StringUtils.IsNullOrEmpty(visitorData)
LogError("Visitor data not found", text)
return invalid
end if

return {
"__version": SESSION_DATA_VERSION
"timestamp": TimeUtils.Now().AsSeconds()
"visitorData": visitorData
}
end function

function ReadSessionDataFromRegistry() as object
sessionData = RegistryUtils.Read(RegistryUtils.INNERTUBE_SESSION_DATA)
if StringUtils.IsNullOrEmpty(sessionData)
return invalid
end if

sessionData = ParseJson(sessionData)
if sessionData = invalid
RegistryUtils.Delete(RegistryUtils.INNERTUBE_SESSION_DATA)
return invalid
end if

timestamp = sessionData.timestamp
nowSeconds = TimeUtils.Now().AsSeconds()
if nowSeconds - timestamp > INNERTUBE_VISITOR_DATA_LIFESPAN
RegistryUtils.Delete(RegistryUtils.INNERTUBE_SESSION_DATA)
return invalid
end if

return sessionData
end function
end namespace
6 changes: 4 additions & 2 deletions playlet-lib/src/components/VideoPlayer/VideoContentTask.bs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "pkg:/components/Services/Invidious/InvidiousService.bs"
function VideoContentTask(input as object) as object
contentNode = input.content
invidiousNode = input.invidious
innertubeNode = input.innertube
preferencesNode = input.preferences
loungeServiceNode = input.loungeService
playletServerPort = input.playletServerPort
Expand All @@ -22,8 +23,9 @@ function VideoContentTask(input as object) as object
backend = preferencesNode["playback.backend"]
if backend = "playlet"
metadata = InnertubeService.GetVideoMetadata(contentNode.videoId, {
cancellation: m.top.cancellation
ctt: loungeServiceNode.ctt
"cancellation": m.top.cancellation
"ctt": loungeServiceNode.ctt
"visitorData": innertubeNode.visitorData
})
else
metadata = service.GetVideoMetadata(contentNode.videoId, { cancellation: m.top.cancellation })
Expand Down
1 change: 1 addition & 0 deletions playlet-lib/src/components/VideoPlayer/VideoPlayer.bs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function StartVideoContentTask(videoContentNode as object)
m.videoContentTask = AsyncTask.Start(Tasks.VideoContentTask, {
content: videoContentNode
invidious: m.top.invidious
innertube: m.top.innertube
preferences: m.top.preferences
loungeService: m.top.loungeService
playletServerPort: m.top.webServer.port
Expand Down
1 change: 1 addition & 0 deletions playlet-lib/src/components/VideoPlayer/VideoPlayer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<field id="notifications" type="node" bind="../../Notifications" />
<field id="videoQueue" type="node" bind="../../VideoQueue" />
<field id="preferences" type="node" bind="../../Preferences" />
<field id="innertube" type="node" bind="../../Innertube" />
<field id="invidious" type="node" bind="../../Invidious" />
<field id="webServer" type="node" bind="../../WebServer" />
<field id="loungeService" type="node" bind="../../LoungeService" />
Expand Down
1 change: 1 addition & 0 deletions playlet-lib/src/components/VideoQueue/VideoQueue.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<field id="player" type="node" />
<field id="nowPlaying" type="node" />

<field id="innertube" type="node" />
<field id="invidious" type="node" />
<field id="notifications" type="node" />
<field id="preferences" type="node" />
Expand Down
1 change: 1 addition & 0 deletions playlet-lib/src/components/VideoQueue/VideoQueueView.bs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ function LoadVideoDetailsIfNeeded() as void

m.loadDetailsTask = AsyncTask.Start(Tasks.VideoQueueViewContentTask, {
videoNodes: m.videosDetailsToLoad
innertube: m.top.innertube
invidious: m.top.invidious
preferences: m.top.preferences
index: indexInLoadingArray
Expand Down
1 change: 1 addition & 0 deletions playlet-lib/src/components/VideoQueue/VideoQueueView.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<field id="jumpToItem" type="integer" alias="queueList.jumpToItem" />
<field id="videoQueue" type="node" />
<field id="appController" type="node" />
<field id="innertube" type="node" />
<field id="invidious" type="node" />
<field id="preferences" type="node" />
<function name="Show" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "pkg:/source/utils/MathUtils.bs"
@asynctask
function VideoQueueViewContentTask(input as object) as object
videoNodes = input.videoNodes
innertubeNode = input.innertube
invidiousNode = input.invidious
preferencesNode = input.preferences
service = new Invidious.InvidiousService(invidiousNode)
Expand All @@ -22,6 +23,7 @@ function VideoQueueViewContentTask(input as object) as object
cancellation: cancellation
tryCount: 1
fetchNext: false
visitorData: innertubeNode.visitorData
}

' TODO:P1: Use InnertubeService.GetVideoInfoBatched instead of loading each video individually
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace VideoQueueViewUtils
videoQueueView = CreateObject("roSGNode", "VideoQueueView")
videoQueueView.videoQueue = videoQueue
videoQueueView.appController = appController
videoQueueView.innertube = videoQueue.innertube
videoQueueView.invidious = videoQueue.invidious
videoQueueView.preferences = videoQueue.preferences
appController@.PushScreen(videoQueueView)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ namespace Http

class PlayletInvidiousBackendRouter extends HttpRouter

function new()
function new(server as object)
super()

m.innertube = server.task.innertube
end function

@get("/playlet-invidious-backend/authorize_token")
Expand Down Expand Up @@ -426,7 +428,8 @@ namespace Http
raw = request.query.raw <> invalid

options = {
raw: raw
"raw": raw
"visitorData": m.innertube.visitorData
}

metadata = InnertubeService.GetVideoMetadata(videoId, options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function SetupRoutes(server as object)
server.UseRouter(new Http.DialRouter(server))
server.UseRouter(new Http.CacheRouter())
server.UseRouter(new Http.RegistryRouter(server))
server.UseRouter(new Http.PlayletInvidiousBackendRouter())
server.UseRouter(new Http.PlayletInvidiousBackendRouter(server))

etags = new Http.EtagUtils()
server.UseRouter(new Http.HttpStaticFilesRouter("/", "libpkg:/www", etags, { staticFiles: true, staticCompressed: true }))
Expand Down
Loading

0 comments on commit 9470860

Please sign in to comment.