mirror of
https://github.com/younesaassila/ttv-lol-pro.git
synced 2025-05-02 15:34:26 +02:00
🚧 WIP
This commit is contained in:
parent
4b5bd5fa2c
commit
fc67664985
@ -1,15 +1,13 @@
|
|||||||
import browser from "webextension-polyfill";
|
import browser from "webextension-polyfill";
|
||||||
import isChrome from "../common/ts/isChrome";
|
import isChrome from "../common/ts/isChrome";
|
||||||
import log from "../common/ts/log";
|
import onBeforeRequest from "./handlers/onBeforeRequest";
|
||||||
import onBeforeHlsRequest from "./handlers/onBeforeHlsRequest";
|
|
||||||
import onBeforeVodRequest from "./handlers/onBeforeVodRequest";
|
|
||||||
import onHeadersReceived from "./handlers/onHeadersReceived";
|
import onHeadersReceived from "./handlers/onHeadersReceived";
|
||||||
import onProxyRequest from "./handlers/onProxyRequest";
|
import onProxyRequest from "./handlers/onProxyRequest";
|
||||||
import onStartupStoreCleanup from "./handlers/onStartupStoreCleanup";
|
import onStartupStoreCleanup from "./handlers/onStartupStoreCleanup";
|
||||||
import onStartupUpdateCheck from "./handlers/onStartupUpdateCheck";
|
import onStartupUpdateCheck from "./handlers/onStartupUpdateCheck";
|
||||||
import updateProxySettings from "./updateProxySettings";
|
import updateProxySettings from "./updateProxySettings";
|
||||||
|
|
||||||
log("🚀 Background script running.");
|
console.info("🚀 Background script running.");
|
||||||
|
|
||||||
// Cleanup the session-related data in the store on startup.
|
// Cleanup the session-related data in the store on startup.
|
||||||
browser.runtime.onStartup.addListener(onStartupStoreCleanup);
|
browser.runtime.onStartup.addListener(onStartupStoreCleanup);
|
||||||
@ -23,15 +21,14 @@ if (!isChrome) {
|
|||||||
urls: ["https://*.ttvnw.net/*"], // Filtered to video-weaver requests in the handler.
|
urls: ["https://*.ttvnw.net/*"], // Filtered to video-weaver requests in the handler.
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Map channel names to HLS playlists.
|
// Map channel names to video-weaver URLs.
|
||||||
browser.webRequest.onBeforeRequest.addListener(onBeforeHlsRequest, {
|
browser.webRequest.onBeforeRequest.addListener(
|
||||||
|
onBeforeRequest,
|
||||||
|
{
|
||||||
urls: ["https://usher.ttvnw.net/api/channel/hls/*"],
|
urls: ["https://usher.ttvnw.net/api/channel/hls/*"],
|
||||||
});
|
},
|
||||||
|
["blocking"]
|
||||||
// TODO: Excluded from proxying.
|
);
|
||||||
browser.webRequest.onBeforeRequest.addListener(onBeforeVodRequest, {
|
|
||||||
urls: ["https://usher.ttvnw.net/vod/*"],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Monitor video-weaver responses.
|
// Monitor video-weaver responses.
|
||||||
browser.webRequest.onHeadersReceived.addListener(onHeadersReceived, {
|
browser.webRequest.onHeadersReceived.addListener(onHeadersReceived, {
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
import { WebRequest } from "webextension-polyfill";
|
|
||||||
|
|
||||||
export default function onBeforeHlsRequest(
|
|
||||||
details: WebRequest.OnBeforeRequestDetailsType
|
|
||||||
): void {
|
|
||||||
// TODO: Get channel name from URL.
|
|
||||||
// TODO: Filter response data to HLS playlists.
|
|
||||||
// TODO: Map channel name to HLS playlists.
|
|
||||||
}
|
|
34
src/background/handlers/onBeforeRequest.ts
Normal file
34
src/background/handlers/onBeforeRequest.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { WebRequest } from "webextension-polyfill";
|
||||||
|
import filterResponseDataWrapper from "../../common/ts/filterResponseDataWrapper";
|
||||||
|
import {
|
||||||
|
twitchApiChannelNameRegex,
|
||||||
|
videoWeaverUrlRegex,
|
||||||
|
} from "../../common/ts/regexes";
|
||||||
|
import store from "../../store";
|
||||||
|
|
||||||
|
export default function onBeforeRequest(
|
||||||
|
details: WebRequest.OnBeforeRequestDetailsType
|
||||||
|
): void | WebRequest.BlockingResponseOrPromise {
|
||||||
|
const match = twitchApiChannelNameRegex.exec(details.url);
|
||||||
|
if (!match) return;
|
||||||
|
const channelName = match[1]?.toLowerCase();
|
||||||
|
if (!channelName) return;
|
||||||
|
|
||||||
|
filterResponseDataWrapper(details, text => {
|
||||||
|
const videoWeaverUrls = text.match(videoWeaverUrlRegex);
|
||||||
|
if (!videoWeaverUrls) return text;
|
||||||
|
console.log(
|
||||||
|
`📺 Found ${videoWeaverUrls.length} video-weaver URLs for ${channelName}.`
|
||||||
|
);
|
||||||
|
const existingVideoWeaverUrls =
|
||||||
|
store.state.videoWeaverUrlsByChannel[channelName] ?? [];
|
||||||
|
const newVideoWeaverUrls = videoWeaverUrls.filter(
|
||||||
|
url => !existingVideoWeaverUrls.includes(url)
|
||||||
|
);
|
||||||
|
store.state.videoWeaverUrlsByChannel[channelName] = [
|
||||||
|
...existingVideoWeaverUrls,
|
||||||
|
...newVideoWeaverUrls,
|
||||||
|
];
|
||||||
|
return text;
|
||||||
|
});
|
||||||
|
}
|
@ -1,8 +0,0 @@
|
|||||||
import { WebRequest } from "webextension-polyfill";
|
|
||||||
|
|
||||||
export default function onBeforeVodRequest(
|
|
||||||
details: WebRequest.OnBeforeRequestDetailsType
|
|
||||||
): void {
|
|
||||||
// TODO: Filter response data to HLS playlists.
|
|
||||||
// TODO: Exclude HLS playlists from proxying.
|
|
||||||
}
|
|
@ -7,16 +7,18 @@ export default function onHeadersReceived(
|
|||||||
details: WebRequest.OnHeadersReceivedDetailsType & {
|
details: WebRequest.OnHeadersReceivedDetailsType & {
|
||||||
proxyInfo?: ProxyInfo;
|
proxyInfo?: ProxyInfo;
|
||||||
}
|
}
|
||||||
): void {
|
): void | WebRequest.BlockingResponseOrPromise {
|
||||||
// Filter to video-weaver responses.
|
// Filter to video-weaver responses.
|
||||||
const host = getHostFromUrl(details.url);
|
const host = getHostFromUrl(details.url);
|
||||||
if (!host || !videoWeaverHostRegex.test(host)) return;
|
if (!host || !videoWeaverHostRegex.test(host)) return;
|
||||||
|
|
||||||
const proxyInfo = details.proxyInfo; // Firefox only.
|
const proxyInfo = details.proxyInfo; // Firefox only.
|
||||||
if (!proxyInfo || proxyInfo.type === "direct")
|
if (!proxyInfo || proxyInfo.type === "direct")
|
||||||
return console.log(`❌ Failed to proxy ${details.url}`);
|
return console.log(`❌ Did not proxy ${details.url}`);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`✅ Proxied ${details.url} through ${proxyInfo.host}:${proxyInfo.port} (${proxyInfo.type})`
|
`✅ Proxied ${details.url} through ${proxyInfo.host}:${proxyInfo.port} (${proxyInfo.type})`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Stream status.
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Proxy } from "webextension-polyfill";
|
import { Proxy } from "webextension-polyfill";
|
||||||
|
import findChannelFromVideoWeaverUrl from "../../common/ts/findChannelFromVideoWeaverUrl";
|
||||||
import getHostFromUrl from "../../common/ts/getHostFromUrl";
|
import getHostFromUrl from "../../common/ts/getHostFromUrl";
|
||||||
import { videoWeaverHostRegex } from "../../common/ts/regexes";
|
import { videoWeaverHostRegex } from "../../common/ts/regexes";
|
||||||
import store from "../../store";
|
import store from "../../store";
|
||||||
@ -11,6 +12,19 @@ export default function onProxyRequest(
|
|||||||
const host = getHostFromUrl(details.url);
|
const host = getHostFromUrl(details.url);
|
||||||
if (!host || !videoWeaverHostRegex.test(host)) return { type: "direct" };
|
if (!host || !videoWeaverHostRegex.test(host)) return { type: "direct" };
|
||||||
|
|
||||||
|
// Check if the channel is whitelisted.
|
||||||
|
const channelName = findChannelFromVideoWeaverUrl(details.url);
|
||||||
|
const isWhitelisted = (channelName: string) => {
|
||||||
|
const whitelistedChannelsLower = store.state.whitelistedChannels.map(
|
||||||
|
channel => channel.toLowerCase()
|
||||||
|
);
|
||||||
|
return whitelistedChannelsLower.includes(channelName.toLowerCase());
|
||||||
|
};
|
||||||
|
if (channelName != null && isWhitelisted(channelName)) {
|
||||||
|
console.log(`✋ Channel ${channelName} is whitelisted.`);
|
||||||
|
return { type: "direct" };
|
||||||
|
}
|
||||||
|
|
||||||
const proxies = store.state.servers;
|
const proxies = store.state.servers;
|
||||||
const proxyInfoArray: ProxyInfo[] = proxies.map(host => {
|
const proxyInfoArray: ProxyInfo[] = proxies.map(host => {
|
||||||
const [hostname, port] = host.split(":");
|
const [hostname, port] = host.split(":");
|
||||||
@ -20,11 +34,11 @@ export default function onProxyRequest(
|
|||||||
port: Number(port) ?? 3128,
|
port: Number(port) ?? 3128,
|
||||||
} as ProxyInfo;
|
} as ProxyInfo;
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`🔄 Proxying ${details.url} through one of: [${proxies.toString()}]`
|
`⌛ Proxying ${details.url} (${channelName ?? "unknown"}) through one of: ${
|
||||||
|
proxies.toString() || "<empty>"
|
||||||
|
}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (proxyInfoArray.length === 0) return { type: "direct" };
|
if (proxyInfoArray.length === 0) return { type: "direct" };
|
||||||
return proxyInfoArray;
|
return proxyInfoArray;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ export default function updateProxySettings() {
|
|||||||
};
|
};
|
||||||
chrome.proxy.settings.set({ value: config, scope: "regular" }, function () {
|
chrome.proxy.settings.set({ value: config, scope: "regular" }, function () {
|
||||||
console.log(
|
console.log(
|
||||||
`Proxying video-weaver requests through one of: [${store.state.servers.toString()}]`
|
`⚙️ Proxying video-weaver requests through one of: ${
|
||||||
|
store.state.servers.toString() || "<empty>"
|
||||||
|
}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
9
src/common/ts/findChannelFromVideoWeaverUrl.ts
Normal file
9
src/common/ts/findChannelFromVideoWeaverUrl.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import store from "../../store";
|
||||||
|
|
||||||
|
export default function findChannelFromVideoWeaverUrl(videoWeaverUrl: string) {
|
||||||
|
const channelName = Object.keys(store.state.videoWeaverUrlsByChannel).find(
|
||||||
|
channelName =>
|
||||||
|
store.state.videoWeaverUrlsByChannel[channelName].includes(videoWeaverUrl)
|
||||||
|
);
|
||||||
|
return channelName ?? null;
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export default function log(...args: any[]) {
|
|
||||||
console.log("[TTV LOL PRO]", ...args);
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
export const TWITCH_URL_REGEX =
|
export const twitchApiChannelNameRegex = /\/hls\/(.+)\.m3u8/i;
|
||||||
/^https?:\/\/(?:(?:www|m)\.)?twitch\.tv\/(?:videos\/)?([A-Z0-9][A-Z0-9_]*)/i;
|
export const twitchWatchPageUrlRegex =
|
||||||
export const TWITCH_API_URL_REGEX = /\/(hls|vod)\/(.+)\.m3u8(?:\?(.*))?$/i;
|
/^https?:\/\/(?:(?:www|m)\.)?twitch\.tv\/(?:videos\/)?(\w+)/i;
|
||||||
export const TTV_LOL_API_URL_REGEX = /\/(?:playlist|vod)\/(.+)\.m3u8/i;
|
|
||||||
export const videoWeaverHostRegex = /^video-weaver\.\w+\.hls\.ttvnw\.net$/i;
|
export const videoWeaverHostRegex = /^video-weaver\.\w+\.hls\.ttvnw\.net$/i;
|
||||||
|
export const videoWeaverUrlRegex =
|
||||||
|
/^https?:\/\/video-weaver\.\w+\.hls\.ttvnw\.net\/v1\/playlist\/.+\.m3u8$/gim;
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import log from "../common/ts/log";
|
import { twitchWatchPageUrlRegex } from "../common/ts/regexes";
|
||||||
import { TWITCH_URL_REGEX } from "../common/ts/regexes";
|
|
||||||
import store from "../store";
|
import store from "../store";
|
||||||
|
|
||||||
log("🚀 Content script running.");
|
console.info("[TTV LOL PRO] 🚀 Content script running.");
|
||||||
|
|
||||||
if (store.readyState === "complete") clearErrors();
|
if (store.readyState === "complete") clearErrors();
|
||||||
else store.addEventListener("load", clearErrors);
|
else store.addEventListener("load", clearErrors);
|
||||||
|
|
||||||
// Clear errors for stream on page load/reload.
|
// Clear errors for stream on page load/reload.
|
||||||
function clearErrors() {
|
function clearErrors() {
|
||||||
const match = TWITCH_URL_REGEX.exec(location.href);
|
const match = twitchWatchPageUrlRegex.exec(location.href);
|
||||||
if (!match) return;
|
if (!match) return;
|
||||||
const [, streamId] = match;
|
const [, streamId] = match;
|
||||||
if (!streamId) return;
|
if (!streamId) return;
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"proxy",
|
"proxy",
|
||||||
"storage",
|
"storage",
|
||||||
"webRequest",
|
"webRequest",
|
||||||
|
"webRequestBlocking",
|
||||||
"https://*.ttvnw.net/*",
|
"https://*.ttvnw.net/*",
|
||||||
"https://www.twitch.tv/*",
|
"https://www.twitch.tv/*",
|
||||||
"https://m.twitch.tv/*",
|
"https://m.twitch.tv/*",
|
||||||
|
@ -36,10 +36,6 @@ const whitelistedChannelsListElement = $(
|
|||||||
$;
|
$;
|
||||||
// Proxies
|
// Proxies
|
||||||
const serversListElement = $("#servers-list") as HTMLOListElement;
|
const serversListElement = $("#servers-list") as HTMLOListElement;
|
||||||
// Privacy
|
|
||||||
const disableVodRedirectCheckboxElement = $(
|
|
||||||
"#disable-vod-redirect-checkbox"
|
|
||||||
) as HTMLInputElement;
|
|
||||||
// Ignored channel subscriptions
|
// Ignored channel subscriptions
|
||||||
const ignoredChannelSubscriptionsListElement = $(
|
const ignoredChannelSubscriptionsListElement = $(
|
||||||
"#ignored-channel-subscriptions-list"
|
"#ignored-channel-subscriptions-list"
|
||||||
@ -84,24 +80,6 @@ function main() {
|
|||||||
const checkbox = e.target as HTMLInputElement;
|
const checkbox = e.target as HTMLInputElement;
|
||||||
store.state.checkForUpdates = checkbox.checked;
|
store.state.checkForUpdates = checkbox.checked;
|
||||||
});
|
});
|
||||||
// Disable VOD proxying
|
|
||||||
disableVodRedirectCheckboxElement.checked = store.state.disableVodRedirect;
|
|
||||||
disableVodRedirectCheckboxElement.addEventListener("change", e => {
|
|
||||||
const checkbox = e.target as HTMLInputElement;
|
|
||||||
if (checkbox.checked) {
|
|
||||||
store.state.disableVodRedirect = checkbox.checked;
|
|
||||||
} else {
|
|
||||||
// Ask for confirmation before enabling VOD proxying.
|
|
||||||
const consent = confirm(
|
|
||||||
"Are you sure?\n\nYour Twitch token (containing sensitive information) will be sent to TTV LOL's API server when watching VODs."
|
|
||||||
);
|
|
||||||
if (consent) {
|
|
||||||
store.state.disableVodRedirect = checkbox.checked;
|
|
||||||
} else {
|
|
||||||
checkbox.checked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Server list
|
// Server list
|
||||||
listInit(serversListElement, "servers", store.state.servers, {
|
listInit(serversListElement, "servers", store.state.servers, {
|
||||||
getPromptPlaceholder: insertMode => {
|
getPromptPlaceholder: insertMode => {
|
||||||
@ -295,9 +273,7 @@ exportButtonElement.addEventListener("click", () => {
|
|||||||
"ttv-lol-pro_backup.json",
|
"ttv-lol-pro_backup.json",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
checkForUpdates: store.state.checkForUpdates,
|
checkForUpdates: store.state.checkForUpdates,
|
||||||
disableVodRedirect: store.state.disableVodRedirect,
|
|
||||||
ignoredChannelSubscriptions: store.state.ignoredChannelSubscriptions,
|
ignoredChannelSubscriptions: store.state.ignoredChannelSubscriptions,
|
||||||
resetPlayerOnMidroll: store.state.resetPlayerOnMidroll,
|
|
||||||
servers: store.state.servers,
|
servers: store.state.servers,
|
||||||
whitelistedChannels: store.state.whitelistedChannels,
|
whitelistedChannels: store.state.whitelistedChannels,
|
||||||
}),
|
}),
|
||||||
|
@ -64,29 +64,6 @@
|
|||||||
</small>
|
</small>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="privacy-section" class="section" hidden>
|
|
||||||
<h2>Privacy</h2>
|
|
||||||
<ul class="options-list">
|
|
||||||
<li>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="disable-vod-redirect-checkbox"
|
|
||||||
id="disable-vod-redirect-checkbox"
|
|
||||||
/>
|
|
||||||
<label for="disable-vod-redirect-checkbox">
|
|
||||||
Disable VOD proxying
|
|
||||||
</label>
|
|
||||||
<br />
|
|
||||||
<small>
|
|
||||||
TTV LOL's API requires your Twitch token (containing sensitive
|
|
||||||
information) to remove ads from VODs. To protect your privacy, and
|
|
||||||
since most ad blockers (like uBlock Origin) already remove ads
|
|
||||||
from VODs, this option is enabled by default.
|
|
||||||
</small>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section
|
<section
|
||||||
id="ignored-channel-subscriptions-section"
|
id="ignored-channel-subscriptions-section"
|
||||||
class="section"
|
class="section"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import browser from "webextension-polyfill";
|
import browser from "webextension-polyfill";
|
||||||
import $ from "../common/ts/$";
|
import $ from "../common/ts/$";
|
||||||
import { TWITCH_URL_REGEX } from "../common/ts/regexes";
|
import { twitchWatchPageUrlRegex } from "../common/ts/regexes";
|
||||||
import store from "../store";
|
import store from "../store";
|
||||||
import type { StreamStatus } from "../types";
|
import type { StreamStatus } from "../types";
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ async function main() {
|
|||||||
const activeTab = tabs[0];
|
const activeTab = tabs[0];
|
||||||
if (!activeTab || !activeTab.url) return;
|
if (!activeTab || !activeTab.url) return;
|
||||||
|
|
||||||
const match = TWITCH_URL_REGEX.exec(activeTab.url);
|
const match = twitchWatchPageUrlRegex.exec(activeTab.url);
|
||||||
if (!match) return;
|
if (!match) return;
|
||||||
const [, streamId] = match;
|
const [, streamId] = match;
|
||||||
if (!streamId) return;
|
if (!streamId) return;
|
||||||
|
@ -3,12 +3,12 @@ import type { State } from "./types";
|
|||||||
export default function getDefaultState() {
|
export default function getDefaultState() {
|
||||||
return {
|
return {
|
||||||
checkForUpdates: false, // No need to check for updates on startup for CRX and XPI installs. The default value is set in the store initializer.
|
checkForUpdates: false, // No need to check for updates on startup for CRX and XPI installs. The default value is set in the store initializer.
|
||||||
disableVodRedirect: true, // Most ad-blockers already remove ads from VODs (VOD proxying requires a Twitch token).
|
|
||||||
ignoredChannelSubscriptions: [], // Some channels might show ads even if you're subscribed to them.
|
ignoredChannelSubscriptions: [], // Some channels might show ads even if you're subscribed to them.
|
||||||
isUpdateAvailable: false,
|
isUpdateAvailable: false,
|
||||||
lastUpdateCheck: 0,
|
lastUpdateCheck: 0,
|
||||||
servers: [],
|
servers: [],
|
||||||
streamStatuses: {},
|
streamStatuses: {},
|
||||||
|
videoWeaverUrlsByChannel: {},
|
||||||
whitelistedChannels: [],
|
whitelistedChannels: [],
|
||||||
} as State;
|
} as State;
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ export type StorageAreaName = "local" | "managed" | "sync";
|
|||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
checkForUpdates: boolean;
|
checkForUpdates: boolean;
|
||||||
disableVodRedirect: boolean;
|
|
||||||
ignoredChannelSubscriptions: string[];
|
ignoredChannelSubscriptions: string[];
|
||||||
isUpdateAvailable: boolean;
|
isUpdateAvailable: boolean;
|
||||||
lastUpdateCheck: number;
|
lastUpdateCheck: number;
|
||||||
servers: string[];
|
servers: string[];
|
||||||
streamStatuses: Record<string, StreamStatus>;
|
streamStatuses: Record<string, StreamStatus>;
|
||||||
|
videoWeaverUrlsByChannel: Record<string, string[]>;
|
||||||
whitelistedChannels: string[];
|
whitelistedChannels: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
src/types.ts
45
src/types.ts
@ -15,51 +15,6 @@ export interface StreamStatusError {
|
|||||||
status: number;
|
status: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum PlaylistType {
|
|
||||||
Playlist = "playlist",
|
|
||||||
VOD = "vod",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Token {
|
|
||||||
adblock?: boolean;
|
|
||||||
authorization: {
|
|
||||||
forbidden: boolean;
|
|
||||||
reason: string;
|
|
||||||
};
|
|
||||||
blackout_enabled?: boolean;
|
|
||||||
channel?: string;
|
|
||||||
channel_id?: number;
|
|
||||||
chansub: {
|
|
||||||
restricted_bitrates?: string[];
|
|
||||||
view_until: number;
|
|
||||||
};
|
|
||||||
ci_gb?: boolean;
|
|
||||||
geoblock_reason?: string;
|
|
||||||
device_id?: string;
|
|
||||||
expires: number;
|
|
||||||
extended_history_allowed?: boolean;
|
|
||||||
game?: string;
|
|
||||||
hide_ads?: boolean;
|
|
||||||
https_required: boolean;
|
|
||||||
mature?: boolean;
|
|
||||||
partner?: boolean;
|
|
||||||
platform?: string;
|
|
||||||
player_type?: string;
|
|
||||||
private?: {
|
|
||||||
allowed_to_view: boolean;
|
|
||||||
};
|
|
||||||
privileged: boolean;
|
|
||||||
role?: string;
|
|
||||||
server_ads?: boolean;
|
|
||||||
show_ads?: boolean;
|
|
||||||
subscriber?: boolean;
|
|
||||||
turbo?: boolean;
|
|
||||||
user_id?: number;
|
|
||||||
user_ip?: string;
|
|
||||||
version: number;
|
|
||||||
vod_id?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/ProxyInfo
|
// From https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/ProxyInfo
|
||||||
export type ProxyInfo = {
|
export type ProxyInfo = {
|
||||||
type: "direct" | "http" | "https" | "socks" | "socks4";
|
type: "direct" | "http" | "https" | "socks" | "socks4";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user