### Preview Plugin Installation Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Allows previewing a plugin before installation by providing its configuration URL. This is useful for verifying plugin details. ```bash curl "http://localhost:11338/Sources/SourceInstallPrompt?url=https://..." ``` -------------------------------- ### GET /Sources/SourceInstall Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Installs a plugin from a provided URL. ```APIDOC ## GET /Sources/SourceInstall ### Description Installs a plugin from a specified URL. ### Method GET ### Endpoint /Sources/SourceInstall ### Parameters #### Query Parameters - **url** (string) - Required - The URL of the plugin configuration JSON. ``` -------------------------------- ### Install Plugin from URL Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Installs a plugin by providing its configuration URL. Ensure the Grayjay server is running locally on port 11338. ```bash curl "http://localhost:11338/Sources/SourceInstall?url=https://plugins.grayjay.app/Youtube/YoutubeConfig.json" ``` -------------------------------- ### POST /Sources/InstallOfficialPlugins Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Installs multiple official plugins by their IDs. ```APIDOC ## POST /Sources/InstallOfficialPlugins ### Description Installs a list of official plugins. ### Method POST ### Endpoint /Sources/InstallOfficialPlugins ### Request Body - **body** (array) - Required - A JSON array of plugin IDs (strings). ``` -------------------------------- ### Install Multiple Official Plugins Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Installs multiple official plugins simultaneously using their unique identifiers. This endpoint requires a POST request with a JSON array of plugin IDs. ```bash curl -X POST "http://localhost:11338/Sources/InstallOfficialPlugins" \ -H "Content-Type: application/json" \ -d '["youtube-id", "odysee-id"]' ``` -------------------------------- ### Manage Sources Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for managing platform plugins, including installation, authentication, and configuration. ```bash curl "http://localhost:11338/Sources/Sources" ``` ```bash curl "http://localhost:11338/Sources/SourcesEnabled" ``` ```bash curl "http://localhost:11338/Sources/SourceDetails?id=source-id" ``` ```bash curl "http://localhost:11338/Sources/SourceEnable?id=source-id" ``` ```bash curl "http://localhost:11338/Sources/SourceDisable?id=source-id" ``` ```bash curl -X POST "http://localhost:11338/Sources/SourcesReorder" \ -H "Content-Type: application/json" \ -d '["source1", "source2", "source3"]' ``` ```bash curl "http://localhost:11338/Sources/SourceLogin?id=source-id" ``` ```bash curl "http://localhost:11338/Sources/SourceLogout?id=source-id" ``` ```bash curl "http://localhost:11338/Sources/OfficialPlugins" ``` -------------------------------- ### Get Application Settings Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves the current application-wide settings for Grayjay. ```bash curl "http://localhost:11338/Settings/Settings" ``` -------------------------------- ### Get Video Chapters Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve chapter information for a given video URL. This allows for navigation within longer videos. ```bash curl "http://localhost:11338/Details/GetVideoChapters?url=https://youtube.com/watch?v=abc" ``` -------------------------------- ### Get Online Synced Devices Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetches a list of only those synchronized devices that are currently online and available. ```bash curl "http://localhost:11338/Sync/GetOnlineDevices" ``` -------------------------------- ### Get All Watch Later Items Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves all videos currently added to the user's watch later queue. This is a GET request to the WatchLater API. ```bash curl "http://localhost:11338/WatchLater/GetAll" ``` -------------------------------- ### Get Pinned Casting Devices Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetches a list of casting devices that have been saved or 'pinned' for quick access. ```bash curl "http://localhost:11338/Casting/PinnedDevices" ``` -------------------------------- ### Get Source-Specific Settings Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves the settings specific to a particular plugin source, identified by its ID. ```bash curl "http://localhost:11338/Settings/SourceSettings?id=source-id" ``` -------------------------------- ### Get Channel Details Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetch detailed information about a specific YouTube channel, including its name, subscriber count, and description. ```bash curl "http://localhost:11338/Channel/Channel?url=https://youtube.com/channel/UC..." ``` -------------------------------- ### Get Pairing URL for New Device Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Generates a unique pairing URL for a new device to initiate synchronization with Grayjay instances. ```bash curl "http://localhost:11338/Sync/GetPairingUrl" ``` -------------------------------- ### GET /Casting/DiscoveredDevices Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Lists devices discovered on the network for casting. ```APIDOC ## GET /Casting/DiscoveredDevices ### Description Retrieves a list of available casting devices. ### Method GET ### Endpoint /Casting/DiscoveredDevices ``` -------------------------------- ### Get DASH Manifest Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Obtain the DASH manifest URL for video playback. Specify video, audio, and subtitle stream indices. ```bash curl "http://localhost:11338/Details/SourceDash?videoIndex=0&audioIndex=0&subtitleIndex=-1" ``` -------------------------------- ### Get HLS Manifest Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve the HLS manifest URL, typically used for live streaming content. ```bash curl "http://localhost:11338/Details/SourceHLS?videoIndex=0" ``` -------------------------------- ### UI Persistence API Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for getting and setting UI state data. ```APIDOC ## GET /Settings/PersistGet ### Description Retrieves UI persistence data for a specific key. ### Method GET ### Endpoint /Settings/PersistGet ### Parameters #### Query Parameters - **key** (string) - Required - The identifier for the UI state data. ## POST /Settings/PersistSet ### Description Sets UI persistence data for a specific key. ### Method POST ### Endpoint /Settings/PersistSet ### Parameters #### Query Parameters - **key** (string) - Required - The identifier for the UI state data. #### Request Body - **data** (object) - Required - The UI state object to persist. ``` -------------------------------- ### Get All Synced Devices Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves a list of all devices currently synchronized with this Grayjay instance. ```bash curl "http://localhost:11338/Sync/GetDevices" ``` -------------------------------- ### Delete Source Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Removes a previously installed source from Grayjay using its unique source ID. This is a simple GET request to the specified endpoint. ```bash curl "http://localhost:11338/Sources/SourceDelete?id=source-id" ``` -------------------------------- ### GET /Subscriptions/Subscriptions Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves a list of all user subscriptions. ```APIDOC ## GET /Subscriptions/Subscriptions ### Description Retrieves all current channel subscriptions. ### Method GET ### Endpoint /Subscriptions/Subscriptions ``` -------------------------------- ### Get Next Home Feed Page Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve the subsequent page of recommendations from the home feed after loading the initial set. ```bash curl "http://localhost:11338/Home/HomeNextPage" ``` -------------------------------- ### Get Discovered Casting Devices Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves a list of all casting devices discovered on the network. This is part of the Casting API. ```bash curl "http://localhost:11338/Casting/DiscoveredDevices" ``` -------------------------------- ### GET /History/HistoryLoad Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves the user's watch history. ```APIDOC ## GET /History/HistoryLoad ### Description Loads the watch history records. ### Method GET ### Endpoint /History/HistoryLoad ``` -------------------------------- ### Get Next Comments Page Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve the next page of comments for a video. Call this after loading the initial set of comments. ```bash curl "http://localhost:11338/Details/CommentsNextPage" ``` -------------------------------- ### Get Next Page of History Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetches the next page of watch history results. This is useful for paginated history views. ```bash curl "http://localhost:11338/History/HistoryNextPage" ``` -------------------------------- ### Get Current Loaded Video Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve details of the video that is currently loaded or being processed by the application. ```bash curl "http://localhost:11338/Details/VideoCurrent" ``` -------------------------------- ### Get Live Chat Window Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve the live chat window for a currently playing live stream. This endpoint is specific to live content. ```bash curl "http://localhost:11338/Details/GetLiveChatWindow" ``` -------------------------------- ### Get Next Search Results Page Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetch the next page of search results. This should be called after an initial search has been performed. ```bash curl "http://localhost:11338/Search/SearchNextPage" ``` -------------------------------- ### Get Next Channel Content Page Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve the next page of content (videos) from a channel's feed. Call this after loading the initial content. ```bash curl "http://localhost:11338/Channel/ChannelContentNextPage" ``` -------------------------------- ### Get Search Suggestions Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve search suggestions based on a given query string. Useful for implementing type-ahead search functionality. ```bash curl "http://localhost:11338/Search/SearchSuggestions?query=prog" ``` -------------------------------- ### Get Previous Searches Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve a list of previously performed searches, effectively providing search history. ```bash curl "http://localhost:11338/Search/PreviousSearches" ``` -------------------------------- ### Get Historical Playback Position Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves the last known playback position for a specific video URL from the watch history. ```bash curl "http://localhost:11338/History/GetHistoricalPosition?url=https://youtube.com/watch?v=abc" ``` -------------------------------- ### Plugin Loading and Initialization Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Handles fetching plugin metadata, initializing default settings, and loading the plugin script into the environment. ```javascript t("Failed to get plugin, check log") console.error("Failed to get plugin", pluginResp); } else { this.Plugin.currentPlugin = JSON.parse(pluginResp.body); this.Plugin.currentPlugin.sourceUrl = url; } this.Plugin.currentPluginIcon = new URL(this.Plugin.currentPlugin.iconUrl, url).href var settingsBefore = this.Plugin.settings; if (Object.keys(settingsBefore).length == 0) { this.Plugin.settings = this.Plugin.currentPlugin.settings; for (let settingIndex in this.Plugin.settings) { const setting = this.Plugin.settings\[settingIndex\]; if (setting.value === undefined) { switch (setting.type?.toLowerCase()) { case "dropdown": if (!isNaN(setting.default)) setting.value = parseInt(setting.default); break; case "boolean": if (setting.default?.toLowerCase() == "true") setting.value = true; else setting.value = false; break; } } } } console.log("Plugin Settings", this.Plugin.settings); let currentPastPlugins = this.pastPluginUrls; currentPastPlugins = currentPastPlugins.filter(x=>x.toLowerCase() != url.toLowerCase()); currentPastPlugins.unshift(url); this.pastPluginUrls = currentPastPlugins; localStorage.setItem("pastPlugins", JSON.stringify(currentPastPlugins)); try { this.Plugin.warnings = pluginGetWarnings(this.Plugin.currentPlugin); } catch(ex) { alert("Failed to validate config, check log") console.error("Failed to validate config", ex); return; } if(!this.Plugin.currentPlugin.scriptUrl) { alert("Misssing plugin script, check log") console.error("Failed to get plugin due to missing script"); } let absScriptUrl = new URL(this.Plugin.currentPlugin.scriptUrl, url).href; console.log("Loading script (Abs):" + absScriptUrl); const scriptResp = httpGETBypass(absScriptUrl, {}, "application/js"); if(pluginResp.code != 200) { alert("Failed to get plugin") console.error("Failed to get plugin", pluginResp); } else { this.Plugin.currentScript = scriptResp.body; try{ //TODO: Load packages const testPluginPackages = pluginUpdateTestPlugin(this.Plugin.currentPlugin); console.log("Required packages:", testPluginPackages); applyPackages(testPluginPackages); if (this.Plugin.loadUsingTag) { this.Plugin.currentPluginError = "" //Create script tag const scriptUrl = absScriptUrl + "?x=" + new Date().getTime(); if (lastScriptTag) lastScriptTag.parentNode.removeChild(lastScriptTag); lastScriptTag = document.createElement('script'); lastScriptTag.src = scriptUrl; lastScriptTag.crossorigin = "anonymous"; lastScriptTag.onerror = function () { Vue.nextTick(() => { this.Plugin.currentPluginError = "Exception loading script: " + scriptUrl; }); } document.getElementsByTagName('body')\[0\].appendChild(lastScriptTag); } else { eval(this.Plugin.currentScript); } const date = new Date(); this.Plugin.lastLoadTime = (date.getHours()+"").padStart(2, '0') + ":" + (date.getMinutes()+"").padStart(2, '0') + ":" + (date.getSeconds() + "").padStart(2, '0'); core.Plugin = this.Plugin; if(this.settings.loginOnReload) { this.loginTestPlugin() } else if(this.settings.enableOnReload) this.testSource(this.Testing.requests.find(x=>x.title == 'enable')); } catch(ex) { alert("Failed to load plugin script, check log"); console.error("Failed to load plugin script", ex); this.Plugin.currentPluginError = "Exception loading script:\n" + ex; } } ``` -------------------------------- ### Execute Main Rendering Loop Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Invokes the sequence of drawing functions and initializes the loader. ```javascript t); drawGradientBackground(); drawTargets(timeMs); drawParticles(timeMs); drawText(); } startLoader(); ``` -------------------------------- ### Initialize and Resize Canvas Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Sets up the canvas context and handles window resizing to maintain aspect ratio and device pixel ratio. Ensures the canvas is correctly scaled for high-density displays. ```javascript const canvas = document.getElementById('loader'); const ctx = canvas.getContext('2d'); let dpr = window.devicePixelRatio || 1; let prevWidth, prevHeight; function resize() { dpr = window.devicePixelRatio || 1; const newWidth = canvas.clientWidth; const newHeight = canvas.clientHeight; canvas.width = Math.floor(newWidth * dpr); canvas.height = Math.floor(newHeight * dpr); ctx.scale(dpr, dpr); // ... (rest of resize logic) } window.addEventListener('resize', resize); resize(); ``` -------------------------------- ### Load Video Recommendations Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve a list of recommended videos based on the provided video URL. Useful for suggesting related content. ```bash curl "http://localhost:11338/Details/RecommendationsLoad?url=https://..." ``` -------------------------------- ### Manage Playlists Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for creating, modifying, and organizing local video playlists. ```bash curl "http://localhost:11338/Playlists/GetAll" ``` ```bash curl "http://localhost:11338/Playlists/Get?id=playlist123" ``` ```bash curl -X POST "http://localhost:11338/Playlists/CreateOrUpdate" \ -H "Content-Type: application/json" \ -d '{ "id": null, "name": "My Favorites", "videos": [] }' ``` ```bash curl -X POST "http://localhost:11338/Playlists/RenamePlaylist?id=playlist123" \ -H "Content-Type: application/json" \ -d '"New Playlist Name"' ``` ```bash curl -X POST "http://localhost:11338/Playlists/AddContentToPlaylists" \ -H "Content-Type: application/json" \ -d '{ "playlistIds": ["playlist1", "playlist2"], "content": { "name": "Video Title", "url": "https://...", "thumbnail": "https://..." } }' ``` ```bash curl "http://localhost:11338/Playlists/RemoveContentFromPlaylist?id=playlist123&index=0" ``` ```bash curl -X DELETE "http://localhost:11338/Playlists/Delete?id=playlist123" ``` -------------------------------- ### Initialize Game Loop Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Sets up the main game loop using requestAnimationFrame for smooth animation. Calls the draw function for each frame. ```javascript let lastFrame = now(); function loop() { const t = now(); const dt = t - lastFrame; lastFrame = t; draw(t, dt); requestAnimationFrame(loop); } requestAnimationFrame(loop); ``` -------------------------------- ### Load Home Feed (Lazy Loading) Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Use this endpoint to load the home feed with lazy loading for better performance. It fetches an initial set of recommendations. ```bash curl "http://localhost:11338/Home/HomeLoadLazy?initialPageSize=20" ``` -------------------------------- ### Get Sync Status Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieves the current synchronization status between Grayjay instances. ```bash curl "http://localhost:11338/Sync/Status" ``` -------------------------------- ### Auto-Select Best Quality Source Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Automatically select the best available quality source for video playback based on network conditions and available streams. ```bash curl "http://localhost:11338/Details/SourceAuto" ``` -------------------------------- ### Load Video Details Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetch detailed information about a specific video, including its metadata, available playback sources, and comments. ```bash curl "http://localhost:11338/Details/VideoLoad?url=https://youtube.com/watch?v=abc123" ``` -------------------------------- ### Manage Downloads Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for handling offline video downloads, storage monitoring, and file exports. ```bash curl "http://localhost:11338/Download/LoadDownloadSources?url=https://youtube.com/watch?v=abc" ``` ```bash curl "http://localhost:11338/Download/Download?id=source-id&videoIndex=0&audioIndex=0&subtitleIndex=-1" ``` ```bash curl "http://localhost:11338/Download/DownloadPlaylist?playlistId=playlist123&pixelCount=1920&bitrate=5000000" ``` ```bash curl "http://localhost:11338/Download/GetDownloading" ``` ```bash curl "http://localhost:11338/Download/GetDownloaded" ``` ```bash curl "http://localhost:11338/Download/GetStorageInfo" ``` ```bash curl -X POST "http://localhost:11338/Download/DeleteDownload" \ -H "Content-Type: application/json" \ -d '{"platform": "YouTube", "value": "abc123"}' ``` ```bash curl -X POST "http://localhost:11338/Download/ExportDownload" \ -H "Content-Type: application/json" \ -d '{"platform": "YouTube", "value": "abc123"}' ``` ```bash curl "http://localhost:11338/Download/ChangeDownloadDirectory" ``` -------------------------------- ### POST /Sync/AddDevice Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Adds a new device for synchronization using a pairing URL. ```APIDOC ## POST /Sync/AddDevice ### Description Registers a new device via a sync URL. ### Method POST ### Endpoint /Sync/AddDevice ### Request Body - **url** (string) - Required - The grayjay://sync/ URL. ``` -------------------------------- ### Connect to Casting Device Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Establishes a connection to a specific casting device using its unique ID. ```bash curl "http://localhost:11338/Casting/Connect?id=device-id" ``` -------------------------------- ### Manage UI persistence data Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve or update UI state settings using the Settings controller. ```bash curl "http://localhost:11338/Settings/PersistGet?key=my-ui-state" ``` ```bash curl -X POST "http://localhost:11338/Settings/PersistSet?key=my-ui-state" \ -H "Content-Type: application/json" \ -d '{"expanded": true}' ``` -------------------------------- ### Plugin State and Authentication Helpers Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Methods for checking login status and updating plugin state information. ```javascript isTestLoggedIn(cb) { pluginIsLoggedIn((isLoggedIn)=> { Vue.nextTick(()=>{ const hasChanged = isLoggedIn != isLoggedIn; this.Plugin.isLoggedIn = isLoggedIn; if(hasChanged) clearPackages(); if(cb) cb(isLoggedIn); }); }, (ex)=> { if(cb) cb(false); }); }, updateStateInfo(cb) { pluginStateInfo((info) => { Vue.nextTick(() => { this.Plugin.canCloneLogin = info.canCloneLogin; if (cb) cb(info); }); }, (ex) => { }); } ``` -------------------------------- ### Import external data Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Use the Import controller to ingest data from backups, external platforms, or URL lists. ```bash # Import from Grayjay backup ZIP curl "http://localhost:11338/Import/ImportZip" ``` ```bash # Import NewPipe subscriptions curl "http://localhost:11338/Import/ImportNewPipe" ``` ```bash # Get user subscriptions from a platform curl "http://localhost:11338/Import/GetUserSubscriptions?id=source-id" ``` ```bash # Get user playlists from a platform curl "http://localhost:11338/Import/GetUserPlaylists?id=source-id" ``` ```bash # Import subscriptions by URL list curl -X POST "http://localhost:11338/Import/ImportSubscriptions" \ -H "Content-Type: application/json" \ -d '["https://youtube.com/channel/UC1", "https://youtube.com/channel/UC2"]' ``` ```bash # Import playlists by URL list curl -X POST "http://localhost:11338/Import/ImportPlaylists" \ -H "Content-Type: application/json" \ -d '["https://youtube.com/playlist?list=PL1", "https://youtube.com/playlist?list=PL2"]' ``` -------------------------------- ### POST /Settings/SettingsSave Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Saves the application settings. ```APIDOC ## POST /Settings/SettingsSave ### Description Updates the application configuration. ### Method POST ### Endpoint /Settings/SettingsSave ### Request Body - **playback** (object) - Optional - Playback preferences. - **downloads** (object) - Optional - Download directory settings. ``` -------------------------------- ### Manage Subscriptions Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for retrieving, modifying, and organizing channel subscriptions and their associated settings. ```bash curl "http://localhost:11338/Subscriptions/Subscriptions" ``` ```bash curl "http://localhost:11338/Subscriptions/IsSubscribed?url=https://youtube.com/channel/UC..." ``` ```bash curl "http://localhost:11338/Subscriptions/Subscribe?url=https://youtube.com/channel/UC..." ``` ```bash curl "http://localhost:11338/Subscriptions/Unsubscribe?url=https://youtube.com/channel/UC..." ``` ```bash curl "http://localhost:11338/Subscriptions/SubscriptionSettings?channelUrl=https://..." ``` ```bash curl -X POST "http://localhost:11338/Subscriptions/UpdateSubscriptionSettings?channelUrl=https://..." \ -H "Content-Type: application/json" \ -d '{ "doFetchVideos": true, "doFetchStreams": true, "doFetchPosts": false, "doFetchLive": true, "doNotifications": true }' ``` ```bash curl "http://localhost:11338/Subscriptions/SubscriptionsLoadLazy?updated=true" ``` ```bash curl "http://localhost:11338/Subscriptions/SubscriptionsCacheLoad" ``` ```bash curl "http://localhost:11338/Subscriptions/SubscriptionGroups" ``` ```bash curl -X POST "http://localhost:11338/Subscriptions/SubscriptionGroupSave" \ -H "Content-Type: application/json" \ -d '{ "id": null, "name": "Tech Channels", "urls": ["https://youtube.com/channel/UC1", "https://youtube.com/channel/UC2"], "image": null }' ``` ```bash curl "http://localhost:11338/Subscriptions/SubscriptionGroupLoad?id=group123&updated=true" ``` -------------------------------- ### Get Canvas Pointer Position Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Calculates the pointer position relative to the canvas element. Handles both mouse and touch events. ```javascript function getPointerPos(evt) { const rect = canvas.getBoundingClientRect(); const cX = evt.touches ? evt.touches[0].clientX : evt.clientX; const cY = evt.touches ? evt.touches[0].clientY : evt.clientY; return { x: (cX - rect.left), y: (cY - rect.top) }; } ``` -------------------------------- ### Load Media on Casting Device Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Loads media content onto the connected casting device. Requires parameters like stream type, resume position, duration, and media details. ```bash curl "http://localhost:11338/Casting/MediaLoad?streamType=video&resumePosition=0&duration=600&videoIndex=0&audioIndex=0&subtitleIndex=-1&title=Video%20Title&thumbnailUrl=https://..." ``` -------------------------------- ### POST /Playlists/CreateOrUpdate Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Creates a new playlist or updates an existing one. ```APIDOC ## POST /Playlists/CreateOrUpdate ### Description Creates or updates a playlist. ### Method POST ### Endpoint /Playlists/CreateOrUpdate ### Request Body - **id** (string) - Optional - Playlist ID. - **name** (string) - Required - Playlist name. - **videos** (array) - Optional - List of videos. ### Request Example { "id": null, "name": "My Favorites", "videos": [] } ``` -------------------------------- ### Import API Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for importing subscriptions, playlists, and data from external sources. ```APIDOC ## GET /Import/ImportZip ### Description Imports data from a Grayjay backup ZIP file. ### Method GET ### Endpoint /Import/ImportZip ## GET /Import/ImportNewPipe ### Description Imports subscriptions from NewPipe. ### Method GET ### Endpoint /Import/ImportNewPipe ## GET /Import/GetUserSubscriptions ### Description Retrieves user subscriptions from a specific platform. ### Method GET ### Endpoint /Import/GetUserSubscriptions ### Parameters #### Query Parameters - **id** (string) - Required - The source platform ID. ## GET /Import/GetUserPlaylists ### Description Retrieves user playlists from a specific platform. ### Method GET ### Endpoint /Import/GetUserPlaylists ### Parameters #### Query Parameters - **id** (string) - Required - The source platform ID. ## POST /Import/ImportSubscriptions ### Description Imports subscriptions via a list of URLs. ### Method POST ### Endpoint /Import/ImportSubscriptions ### Request Body - **urls** (array) - Required - List of channel URLs. ## POST /Import/ImportPlaylists ### Description Imports playlists via a list of URLs. ### Method POST ### Endpoint /Import/ImportPlaylists ### Request Body - **urls** (array) - Required - List of playlist URLs. ``` -------------------------------- ### Save Application Settings Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Saves updated application settings. This POST request requires a JSON body containing the settings to be modified, such as playback quality or download directory. ```bash curl -X POST "http://localhost:11338/Settings/SettingsSave" \ -H "Content-Type: application/json" \ -d '{ "playback": { "preferredQuality": 1080, "primaryLanguage": "en" }, "downloads": { "directory": "/path/to/downloads" } }' ``` -------------------------------- ### Settings Persistence Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Functions to save plugin settings and application configuration to local storage. ```javascript savePluginSettings() { var settings = this.Plugin.settings; console.log(settings); this.reloadPlugin(); }, saveSettings() { let settingsStr = JSON.stringify(this.settings); localStorage.setItem("settings", settingsStr); } ``` -------------------------------- ### Initialize Vue Plugin Testing Interface Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Initializes the Vue instance with data structures for plugin management, testing, and integration logging. ```javascript IS_TESTING = true; let lastScriptTag = null; let shouldDevLog = true; let shouldLoginCheck = true; let core = {}; new Vue({ el: '#app', data: { searchTestMethods: "", page: "Plugin", LAST_DEV_URLS: [], pastPluginUrls: [], settings: {}, support: { SUPPORT_INTEGRATION: true, SUPPORT_TESTING: true }, Integration: { lastLogIndex: -1, lastLogDevID: "", logs: [], httpExchanges: [], lastInjectTime: "", showHttpRequests: false }, Plugin: { loadUsingTag: false, newPluginUrl: "", packagesOverridden: packageOverridesEnabled, currentPluginUrl: "", currentPlugin: null, currentPluginError: "", currentScript: "", lastLoadTime: "", didInitialLoad: false, enableOnReload: false, isLoggedIn: false, settings: {} }, TestSystem: { tests: [], states: {}, selected: {} }, Testing: { requests: sourceDocs.map(x=>{ x.parameters.forEach(y=>y.value = null); if(sourceDocUrls && sourceDocUrls[x.title]) x.docUrl = sourceDocUrls[x.title]; return x; }), lastResult: "", lastResultError: "" } }, mounted() { core.reloadPlugin = () => { Vue.nextTick(() => this.reloadPlugin()) }; core.loadPlugin = (url) => { this.loadPlugin(url); }; let existing = localStorage.getItem("pastPlugins"); if(!existing) existing = []; else existing = JSON.parse(existing); let settingsStr = localStorage.getItem("settings"); if(!settingsStr) this.settings = {}; else this.settings = JSON.parse(settingsStr); this.pastPluginUrls = existing.slice(0, 5); if (this.LAST_DEV_URLS && this.LAST_DEV_URLS.length > 0) this.pastPluginUrls = this.LAST_DEV_URLS.concat(existing.slice(0, 5)); this.loadOverrides(); window.onerror = (event, source, lineno, colno, error)=>{ Vue.nextTick(()=>{ if(error) this.Plugin.currentPluginError = error + " (" + lineno + ", " + colno + ")"; else this.Plugin.currentPluginError = "There is an error in your script, check console for info"; }); }; setInterval(()=>{ try{ if(!this.Plugin.currentPlugin || !shouldDevLog) return; getDevLogs(this.Integration.lastLogIndex, (newLogs)=> { if(newLogs.length > 0) { let firstLog = newLogs[0]; let lastLog = newLogs[newLogs.length - 1]; Vue.nextTick(()=>{ let lastDevId = this.Integration.lastLogDevID; this.Integration.lastLogDevID = lastLog.devId; this.Integration.lastLogIndex = lastLog.id; for(i = 0; i < newLogs.length; i++) { const log = newLogs[i]; console.log("Log", log); if(lastDevId != log.devId) { this.Integration.logs = []; lastDevId = log.devId; this.Integration.logs.unshift({ id: -1, devId: lastDevId, message: "New Dev Session: " + lastDevId }); } this.Integration.logs.unshift(log) }; }); } }); if(this.Integration.showHttpRequests) { getDevHttpExchanges((exchanges)=>{ Vue.nextTick(()=>{ for(i = 0; i < exchanges.length; i++) { exchanges[i].response.show = false; this.Integration.httpExchanges.unshift(exchanges[i]); } }); }); } if (this.page == "TestSystem") { getDevTestSystemStates((states) => { Vue.nextTick(() => { this.TestSystem.tests = states.tests; for (let test of states.tests) { this.TestSystem.states[test.test.variable] = test; } }); }) } } catch(ex) { console.error("Failed update", ex); } }, 1000); setInterval(()=>{ try{ if(shouldLoginCheck) this.isTestLoggedIn(); }catch(ex){} }, 2500); setInterval(() => { this.updateStateInfo(); }, 5000) }, methods: { loadOverrides() { let overridesExisting = localStorage.getItem("overrides"); if(overridesExisting && overridesExisting != "undefined") { try{ const overrides = JSON.parse(overridesExisting); for(override in this.Plugin.packagesOverridden) { if(overrides[override]) this.Plugin.packagesOverridden[override] = true; } } catch(ex) { console.error(ex); } } this.Plugin.didInitialLoad = true; }, saveOverrides() { if(this.Plugin.packagesOverridden && this.Plugin.didInitialLoad) { let overridesExisting = JSON.stringify(this.Plugin.packagesOverridden); localStorage.setItem("overrides", overridesExisting); } }, loadPlugin(url) { Vue.nextTick(()=>{ this.Plugin.currentPluginUrl = url; this.reloadPlugin(); }); }, deletePastPlugin(url) { let currentPastPlugins = this.pastPluginUrls; currentPastPlugins = currentPastPlugins.filter(x=>x.toLowerCase() != url.toLowerCase()); this.pastPluginUrls = currentPastPlugins; localStorage.setItem("pastPlugins", JSON.stringify(currentPastPlugins)); }, loginCloneTestPlugin() { pluginLoginCloneTestPlugin(); setTimeout(() => { reloadPackages(); this.isTestLoggedIn((loggedIn) => { if (loggedIn && this.settings.enableOnReload) this.testSource(this.Testing.requests.find(x => x.title == 'enable')); }); }, 1000); }, loginTestPlugin() { pluginLoginTestPlugin(); setTimeout(()=>{ reloadPackages(); this.isTestLoggedIn((loggedIn)=>{ if(loggedIn && this.settings.enableOnReload) this.testSource(this.Testing.requests.find(x=>x.title == 'enable')); }); }, 1000); }, captchaTestPlugin() { captchaLoginTestPlugin(); }, logoutTestPlugin() { pluginLogoutTestPlugin(); }, reloadPlugin() { const url = this.Plugin.currentPluginUrl; const pluginResp = httpGETBypass(url, {}, "text/json"); if(pluginResp.code != 200) { aler ``` -------------------------------- ### Send Video to Another Device Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Sends a video URL and playback position to a specific synced device. Requires the target device's key and video details. ```bash curl "http://localhost:11338/Sync/SendToDevice?device=device-key&url=https://youtube.com/watch?v=abc&position=0" ``` -------------------------------- ### Load Channel Content Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Retrieve a list of videos uploaded by a specific channel. This endpoint is used to display a channel's video feed. ```bash curl "http://localhost:11338/Channel/ChannelContentLoad?url=https://..." ``` -------------------------------- ### POST /WatchLater/Add Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Adds a video to the watch later queue. ```APIDOC ## POST /WatchLater/Add ### Description Adds a video object to the watch later list. ### Method POST ### Endpoint /WatchLater/Add ### Request Body - **video** (object) - Required - Contains name, url, and thumbnail fields. ``` -------------------------------- ### Validate Sync Device Info Format Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Validates the format of sync device information before adding a new device. Requires a POST request with the device URL in JSON. ```bash curl -X POST "http://localhost:11338/Sync/ValidateSyncDeviceInfoFormat" \ -H "Content-Type: application/json" \ -d '{"url": "grayjay://sync/..."}' ``` -------------------------------- ### Configure NixOS FHS Environment Source: https://github.com/videostreaming/grayjay.desktop/blob/master/README.md Use this NixOS configuration to run Grayjay within a Filesystem Hierarchy Standard environment with required dependencies. ```nix (pkgs.buildFHSEnv { name = "fhs"; targetPkgs = _: with pkgs; [ libz icu libgbm openssl # For updater xorg.libX11 xorg.libXcomposite xorg.libXdamage xorg.libXext xorg.libXfixes xorg.libXrandr xorg.libxcb gtk3 glib nss nspr dbus atk cups libdrm expat libxkbcommon pango cairo udev alsa-lib mesa libGL libsecret ]; }).env ``` -------------------------------- ### Update Watch Progress Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Record the user's current watch progress for a video, specified by URL and playback position in milliseconds. ```bash curl "http://localhost:11338/Details/WatchProgress?url=https://...&position=120000" ``` -------------------------------- ### Queue Test System Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Methods for queuing individual or all available tests in the system. ```javascript queueTestSystem(name, metadata) { queueTestSystem(name, metadata); }, queueTestSystemAll() { for (let test of this.TestSystem.tests) { queueTestSystem(test.test.variable, {}); } } ``` -------------------------------- ### Add Pinned Casting Device Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Saves a discovered casting device to the pinned list for future use. Requires a POST request with device details in JSON format. ```bash curl -X POST "http://localhost:11338/Casting/AddPinnedDevice" \ -H "Content-Type: application/json" \ -d '{ "id": "device-id", "name": "Living Room TV", "type": 1, "addresses": ["192.168.1.100"] }' ``` -------------------------------- ### Target Spawning Logic Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Continuously spawns new target objects at random positions and speeds. The spawn rate increases as the animation progresses. Includes logic to delay spawning if not playing. ```javascript function spawnTarget() { if (loaderFinished) return; if (!isPlaying) { setTimeout(spawnTarget, 500); return; } const radius = rand(MIN_RADIUS, MAX_RADIUS); const x = rand(radius, canvas.clientWidth - radius); const y = rand(radius, canvas.clientHeight - radius - 60); const speed = rand(.1, 1.1); const angle = rand(0, TAU); const vx = Math.cos(angle) * speed; const vy = Math.sin(angle) * speed; const alpha = rand(150, 255) | 0; targets.push(new Target(x, y, radius, vx, vy, alpha)); const delay = (1000 / spawnRate) | 0; setTimeout(spawnTarget, delay); } ``` -------------------------------- ### Add New Device by Pairing URL Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Adds a new synchronized device to Grayjay using its pairing URL. This POST request requires the URL in a JSON payload. ```bash curl -X POST "http://localhost:11338/Sync/AddDevice" \ -H "Content-Type: application/json" \ -d '{"url": "grayjay://sync/base64encodedinfo"}' ``` -------------------------------- ### Loader Initialization and Control Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Functions to manage the state of the loader animation. `startLoader` prepares for animation, `finishLoader` stops it, and `stopAndResetLoader` stops and resets score/targets. ```javascript function startLoader() { loaderFinished = false; isPlaying = false; score = 0; spawnRate = MIN_SPAWN_RATE; particles.length = 0; if (targets.length === 0) prepopulateIdleTargets(); } function finishLoader() { loaderFinished = true; particles.length = 0; isPlaying = false; } function stopAndResetLoader() { if (score > 0) { const elapsed = (now() - playStartTime) / 1000; toast(`Nice! score ${score} | ${(score / elapsed).toFixed(1)} / s`); } loaderFinished = true; isPlaying = false; score = 0; targets.length = 0; particles.length = 0; } ``` -------------------------------- ### Pre-populate Idle Targets Source: https://github.com/videostreaming/grayjay.desktop/blob/master/loadergame.html Fills the screen with a set number of targets when the loader is idle or not actively playing. These targets move slowly and have lower alpha values. ```javascript function prepopulateIdleTargets() { for (let i = 0; i < IDLE_INITIAL_TARGETS; i++) { const radius = rand(MIN_RADIUS, MAX_RADIUS); const x = rand(radius, canvas.clientWidth - radius); const y = rand(radius, canvas.clientHeight - radius - 60); const speed = rand(.05, .35) * IDLE_SPEED_MULTIPLIER; const angle = rand(0, TAU); const vx = Math.cos(angle) * speed; const vy = Math.sin(angle) * speed; const alpha = rand(60, 110) | 0; targets.push(new Target(x, y, radius, vx, vy, alpha)); } } ``` -------------------------------- ### Load Video Comments Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Fetch comments associated with a specific video URL. This endpoint is used to display user comments. ```bash curl "http://localhost:11338/Details/CommentsLoad?url=https://..." ``` -------------------------------- ### Save Source-Specific Settings Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Saves settings for a specific plugin source. This POST request requires the source ID and a JSON body with the settings to update. ```bash curl -X POST "http://localhost:11338/Settings/SourceSettingsSave?id=source-id" \ -H "Content-Type: application/json" \ -d '{"setting1": "value1"}' ``` -------------------------------- ### POST /Subscriptions/UpdateSubscriptionSettings Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Updates the notification and fetching settings for a specific channel subscription. ```APIDOC ## POST /Subscriptions/UpdateSubscriptionSettings ### Description Updates subscription settings for a specific channel. ### Method POST ### Endpoint /Subscriptions/UpdateSubscriptionSettings ### Parameters #### Query Parameters - **channelUrl** (string) - Required - The URL of the channel to update. #### Request Body - **doFetchVideos** (boolean) - Optional - Fetch videos. - **doFetchStreams** (boolean) - Optional - Fetch streams. - **doFetchPosts** (boolean) - Optional - Fetch posts. - **doFetchLive** (boolean) - Optional - Fetch live content. - **doNotifications** (boolean) - Optional - Enable notifications. ### Request Example { "doFetchVideos": true, "doFetchStreams": true, "doFetchPosts": false, "doFetchLive": true, "doNotifications": true } ``` -------------------------------- ### POST /Sources/SourcesReorder Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Updates the display order of enabled sources. ```APIDOC ## POST /Sources/SourcesReorder ### Description Reorders the list of sources. ### Method POST ### Endpoint /Sources/SourcesReorder ### Request Body - **sources** (array) - Required - List of source IDs in the desired order. ### Request Example ["source1", "source2", "source3"] ``` -------------------------------- ### Add to Watch Later Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Adds a video to the watch later queue. This requires a POST request with a JSON body containing video details like title, URL, and thumbnail. ```bash curl -X POST "http://localhost:11338/WatchLater/Add" \ -H "Content-Type: application/json" \ -d '{ "video": { "name": "Video Title", "url": "https://youtube.com/watch?v=abc", "thumbnail": "https://..." } }' ``` -------------------------------- ### Search API Source: https://context7.com/videostreaming/grayjay.desktop/llms.txt Endpoints for content discovery across all enabled source plugins, supporting videos, channels, and playlists. ```APIDOC ## POST /Search/SearchLoadLazy ### Description Searches for content with lazy loading and filtering capabilities. ### Method POST ### Endpoint /Search/SearchLoadLazy ### Query Parameters - **Content-Type**: application/json - Required - Specifies the request body format. ### Request Body - **type** (integer) - Required - The type of content to search for (e.g., 1 for videos). - **query** (string) - Required - The search query string. - **order** (string) - Required - The order of search results (e.g., 'relevance'). - **filters** (object) - Optional - An object containing search filters. - **excludePlugins** (array) - Optional - An array of plugin names to exclude from the search. ### Request Example ```json { "type": 1, "query": "programming tutorial", "order": "relevance", "filters": {}, "excludePlugins": [] } ``` ## GET /Search/SearchSuggestions ### Description Retrieves search suggestions based on a query. ### Method GET ### Endpoint /Search/SearchSuggestions ### Query Parameters - **query** (string) - Required - The search query to get suggestions for. ## GET /Search/SearchNextPage ### Description Retrieves the next page of search results. ### Method GET ### Endpoint /Search/SearchNextPage ## GET /Search/PreviousSearches ### Description Retrieves the history of previous searches. ### Method GET ### Endpoint /Search/PreviousSearches ## GET /Search/IsContentDetailsUrl ### Description Checks if a given URL is a content details URL. ### Method GET ### Endpoint /Search/IsContentDetailsUrl ### Query Parameters - **url** (string) - Required - The URL to check. ``` -------------------------------- ### Execute Plugin Test Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Runs a plugin test function with provided parameters and handles potential CaptchaRequiredException errors. ```javascript h > 0) parameterVals[0] = this.Plugin.currentPlugin; else parameterVals.push(this.Plugin.currentPlugin); if(parameterVals.length > 1) parameterVals[1] = settingsToUse; else parameterVals.push(settingsToUse); } const func = source[name]; if(!func) alert("Test func not found"); try { const result = func(...parameterVals); console.log("Result for " + req.title, result); this.Testing.lastResult = "//Results [" + name + "]\n" + JSON.stringify(result, null, 3); this.Testing.lastResultError = ""; } catch(ex) { if(ex.plugin_type == "CaptchaRequiredException") { let shouldCaptcha = confirm("Do you want to request captcha?"); if(shouldCaptcha) { pluginCaptchaTestPlugin(ex.url, ex.body); } } console.error("Failed to run test for " + req.title, ex); this.Testing.lastResult = "" if(ex.message) this.Testing.lastResultError = "//Results [" + name + "]\n\n" + "Error: " + ex.message + "\n\n" + ex.stack; else this.Testing.lastResultError = "//Results [" + name + "]\n\n" + "Error: " + ex; } ``` -------------------------------- ### Plugin Source Testing Source: https://github.com/videostreaming/grayjay.desktop/blob/master/Grayjay.ClientServer/Developer/Embed/index.html Executes test requests against a plugin source with specific parameters and settings. ```javascript testSource(req) { const name = req.title; const parameterVals = req.parameters.map(x=>{ if(x.value && x.value.startsWith && x.value.startsWith("json:")) return JSON.parse(x.value.substring(5)); return x.value }); let settingsToUse = \_\_DEV\_SETTINGS; for (let setting of this.Plugin?.currentPlugin?.settings ?? \[\]) { const settingLocal = this.Plugin.settings.find(x => x.variable == setting.variable); if (settingLocal) settingsToUse\[setting.variable\] = settingLocal.value; if (typeof settingsToUse\[setting.variable\] == "undefined") { switch (setting?.type?.toLowerCase()) { case "boolean": settingsToUse\[setting.variable\] = setting.default === 'true'; break; case "dropdown": let dropDownIndex = parseInt(setting.default); if (dropDownIndex) { settingsToUse\[setting.variable\] = setting.options\[dropDownIndex\]; } break; } } } if(name == "enable") { if(parameterVals.lengt ```