Compare commits
	
		
			8 Commits
		
	
	
		
			archive/va
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6dadf326ac | |||
| 809803a194 | |||
| 2c6df73d02 | |||
|  | 6407c1b072 | ||
|  | b9d99891db | ||
|  | 48b73a89bc | ||
|  | 82f4a3e6ec | ||
| df0e311dbc | 
							
								
								
									
										43
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,3 +1,42 @@ | |||||||
| # PeerTube plugin Quickstart | # Auto Import YouTube | ||||||
|  |  | ||||||
| See https://docs.joinpeertube.org/#/contribute-plugins?id=write-a-plugintheme | ## Config | ||||||
|  |  | ||||||
|  | To use this plugin, you need to give some valid admins credential inside the plugin's settings. | ||||||
|  |  | ||||||
|  | After this you have to specify some YouTube Channel who need to be bind with a PeerTube Channel. | ||||||
|  | For this you have to use this format inside the plugins's setting. Into `URL list of Youtube channel to synchronize`'s text area. : | ||||||
|  |  | ||||||
|  | ```json | ||||||
|  | [ | ||||||
|  |    { | ||||||
|  |        "address":"https://www.youtube.com/feeds/videos.xml?channel_id=${MyYouTubeChannelID}", | ||||||
|  |        "ChannelId":"MyPeertubeChannelId" | ||||||
|  |    } , | ||||||
|  |    ... | ||||||
|  | ] | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | This an array of object who's in this format : | ||||||
|  |  | ||||||
|  | ```ts | ||||||
|  | type SettingsContent = { | ||||||
|  |   address: string; | ||||||
|  |   channelId: string; | ||||||
|  |   timeloop?: number; | ||||||
|  | }; | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### address | ||||||
|  |  | ||||||
|  | For exemple, to the Youtube channel : `https://www.youtube.com/channel/YouTube`, the channel id is `UCBR8-60-B28hp2BmDPdntcQ`. You can get it when you're clicking in the channel button on the video player. (He's not Highlighted by YouTube. Cheer Up !)   | ||||||
|  | So you need to specify the following address inside your configuration : `https://www.youtube.com/feeds/videos.xml?channel_id=UCBR8-60-B28hp2BmDPdntcQ`. | ||||||
|  |  | ||||||
|  | ### channelId | ||||||
|  |  | ||||||
|  | The peertube's channel id is a number associated to a peertube's channel. He's unique per channel inside a same instance. | ||||||
|  |  | ||||||
|  | ### timeloop | ||||||
|  |  | ||||||
|  | It's represent the time between two update of the videos list.   | ||||||
|  | It's not needful to specify the timeloop. The default value is set to 5 minutes. | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| // Api request lib | // Api request lib | ||||||
| import fetch, { FetchError, Headers } from "node-fetch"; | import fetch, { Headers } from "node-fetch"; | ||||||
| import { URL, URLSearchParams } from "url"; | import { URL, URLSearchParams } from "url"; | ||||||
|  |  | ||||||
| namespace PeerTubeRequester { | namespace PeerTubeRequester { | ||||||
|   export type Config = { |   export type Config = { | ||||||
|     domain_name: string | URL; |     domainName: string | URL; | ||||||
|     username: string; |     username: string; | ||||||
|     password: string; |     password: string; | ||||||
|   }; |   }; | ||||||
| @@ -17,28 +17,29 @@ type UploadInstruction = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| class PeerTubeRequester { | class PeerTubeRequester { | ||||||
|   readonly domain_name: URL; |   readonly domainName: URL; | ||||||
|   readonly username: string; |   readonly username: string; | ||||||
|   readonly password: string; |   readonly password: string; | ||||||
|  |  | ||||||
|   constructor(readonly config: PeerTubeRequester.Config) { |   constructor(readonly config: PeerTubeRequester.Config) { | ||||||
|     this.domain_name = new URL("/", config.domain_name); |     this.domainName = new URL("/", config.domainName); | ||||||
|     this.username = config.username; |     this.username = config.username; | ||||||
|     this.password = config.password; |     this.password = config.password; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private async requestAuthToken(): Promise<any> { |   async requestAuthToken(): Promise<any> { | ||||||
|     let response = await fetch( |     let response = await fetch( | ||||||
|       new URL(`/api/v1/oauth-clients/local`, this.domain_name) |       new URL(`/api/v1/oauth-clients/local`, this.domainName) | ||||||
|     ); |     ); | ||||||
|     if (!response.ok) { |     if (!response.ok) { | ||||||
|       throw new Error(response.statusText); // CRASH |       throw new Error("Cannot get client credentials : " + response.statusText); // CRASH | ||||||
|     } |     } | ||||||
|     const { client_id, client_secret } = await response.json(); |     const { client_id: clientId, client_secret: clientSecret } = | ||||||
|  |       await response.json(); | ||||||
|  |  | ||||||
|     const client_info: { [key: string]: string } = { |     const clientInfo: { [key: string]: string } = { | ||||||
|       client_id, |       client_id: clientId, | ||||||
|       client_secret, |       client_secret: clientSecret, | ||||||
|       grant_type: "password", |       grant_type: "password", | ||||||
|       response_type: "code", |       response_type: "code", | ||||||
|       username: this.username, |       username: this.username, | ||||||
| @@ -46,14 +47,14 @@ class PeerTubeRequester { | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let myParams = new URLSearchParams(); |     let myParams = new URLSearchParams(); | ||||||
|     for (const key in client_info) myParams.append(key, client_info[key]); |     for (const key in clientInfo) myParams.append(key, clientInfo[key]); | ||||||
|  |  | ||||||
|     response = await fetch(new URL(`/api/v1/users/token`, this.domain_name), { |     response = await fetch(new URL(`/api/v1/users/token`, this.domainName), { | ||||||
|       method: "post", |       method: "post", | ||||||
|       body: myParams, |       body: myParams, | ||||||
|     }); |     }); | ||||||
|     if (!response.ok) { |     if (!response.ok) { | ||||||
|       throw new Error(response.statusText); // CRASH |       throw new Error("Cannot get access Token : " + response.statusText); // CRASH | ||||||
|     } |     } | ||||||
|     const { access_token: accessToken } = await response.json(); |     const { access_token: accessToken } = await response.json(); | ||||||
|     return accessToken; |     return accessToken; | ||||||
| @@ -67,7 +68,7 @@ class PeerTubeRequester { | |||||||
|     for (const key in message) myUploadForm.append(key, message[key]); |     for (const key in message) myUploadForm.append(key, message[key]); | ||||||
|  |  | ||||||
|     const response = await fetch( |     const response = await fetch( | ||||||
|       new URL(`/api/v1/videos/imports`, this.domain_name), |       new URL("/api/v1/videos/imports", this.domainName), | ||||||
|       { |       { | ||||||
|         method: "post", |         method: "post", | ||||||
|         headers: myHeader, |         headers: myHeader, | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -9,6 +9,7 @@ | |||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@types/node-fetch": "^2.5.11", |         "@types/node-fetch": "^2.5.11", | ||||||
|         "form-data": "^4.0.0", |         "form-data": "^4.0.0", | ||||||
|  |         "listener-rss": "^0.0.3", | ||||||
|         "listener-rss-aggregator": "^0.0.5", |         "listener-rss-aggregator": "^0.0.5", | ||||||
|         "node-fetch": "^2.6.1" |         "node-fetch": "^2.6.1" | ||||||
|       }, |       }, | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| { | { | ||||||
|   "name": "peertube-plugin-auto-import-ytb", |   "name": "peertube-plugin-auto-import-ytb", | ||||||
|   "description": "PeerTube plugin quickstart", |   "description": "Peertube plugin to auto import videos from a youtube channel to a local peertube channel", | ||||||
|   "version": "0.0.1", |   "version": "0.0.2", | ||||||
|   "author": "AmauryJOLY", |   "author": "AmauryJOLY", | ||||||
|   "bugs": "https://framagit.org/framasoft/peertube/peertube-plugin-quickstart/issues", |   "bugs": "https://zeteo.me/gitea/Outils-PeerTube/peertube-plugin-auto-import-ytb/issues", | ||||||
|   "clientScripts": [], |   "clientScripts": [], | ||||||
|   "css": [], |   "css": [], | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
| @@ -13,7 +13,7 @@ | |||||||
|   "engine": { |   "engine": { | ||||||
|     "peertube": ">=3.2.0" |     "peertube": ">=3.2.0" | ||||||
|   }, |   }, | ||||||
|   "homepage": "https://framagit.org/framasoft/peertube/peertube-plugin-quickstart", |   "homepage": "https://zeteo.me/gitea/Outils-PeerTube/peertube-plugin-auto-import-ytb", | ||||||
|   "keywords": [ |   "keywords": [ | ||||||
|     "peertube", |     "peertube", | ||||||
|     "plugin" |     "plugin" | ||||||
| @@ -34,6 +34,7 @@ | |||||||
|     "@types/node-fetch": "^2.5.11", |     "@types/node-fetch": "^2.5.11", | ||||||
|     "form-data": "^4.0.0", |     "form-data": "^4.0.0", | ||||||
|     "listener-rss-aggregator": "^0.0.5", |     "listener-rss-aggregator": "^0.0.5", | ||||||
|  |     "listener-rss": "^0.0.3", | ||||||
|     "node-fetch": "^2.6.1" |     "node-fetch": "^2.6.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										79
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								src/main.ts
									
									
									
									
									
								
							| @@ -10,7 +10,8 @@ type ListenerData = ListenerRss.Config & { | |||||||
| let myManager: ListenerRssAggregator; | let myManager: ListenerRssAggregator; | ||||||
| let listenersDataBinding = new Map<string, ListenerData>(); | let listenersDataBinding = new Map<string, ListenerData>(); | ||||||
| let logger: any; | let logger: any; | ||||||
| let peertube: PeerTubeRequester; | let peertube: PeerTubeRequester | undefined = undefined; | ||||||
|  | let goodPeertubeCredential: boolean = false; | ||||||
|  |  | ||||||
| import * as path from "path"; | import * as path from "path"; | ||||||
| import fs from "fs"; | import fs from "fs"; | ||||||
| @@ -29,6 +30,18 @@ async function register({ | |||||||
|     type: "input-textarea", |     type: "input-textarea", | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   registerSetting({ | ||||||
|  |     name: "admin-name", | ||||||
|  |     label: "Admin Username", | ||||||
|  |     type: "input", | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   registerSetting({ | ||||||
|  |     name: "admin-password", | ||||||
|  |     label: "Admin Password", | ||||||
|  |     type: "input-password", | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   logger.debug("setting register"); |   logger.debug("setting register"); | ||||||
|   fs.appendFileSync(path.join(basePath, "/storage.bd"), ""); |   fs.appendFileSync(path.join(basePath, "/storage.bd"), ""); | ||||||
|  |  | ||||||
| @@ -37,20 +50,36 @@ async function register({ | |||||||
|   ); |   ); | ||||||
|   myManager = new ListenerRssAggregator(configAggregator); |   myManager = new ListenerRssAggregator(configAggregator); | ||||||
|  |  | ||||||
|   peertube = new PeerTubeRequester({ |  | ||||||
|     domain_name: "http://localhost:9000", |  | ||||||
|     username: "root", |  | ||||||
|     password: "test", |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   logger.debug("Aggregator created"); |   logger.debug("Aggregator created"); | ||||||
|  |  | ||||||
|   const inputs = await settingsManager.getSetting("ytb-urls"); |   const settingYtbUrls = await settingsManager.getSetting("ytb-urls"); | ||||||
|   if (inputs) await addListeners(inputs); |   if (settingYtbUrls) await addListeners(settingYtbUrls); | ||||||
|  |  | ||||||
|   logger.debug("Config loaded"); |   const settingCredentials: any = await settingsManager.getSettings([ | ||||||
|  |     "admin-name", | ||||||
|  |     "admin-password", | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   if (settingCredentials["admin-name"] && settingCredentials["admin-password"]) | ||||||
|  |     apiRequestInitializer({ | ||||||
|  |       domainName: peertubeHelpers.config.getWebserverUrl(), | ||||||
|  |       username: settingCredentials["admin-name"], | ||||||
|  |       password: settingCredentials["admin-password"], | ||||||
|  |     }); | ||||||
|  |   logger.debug("Actual config loaded"); | ||||||
|  |  | ||||||
|   settingsManager.onSettingsChange(async (settings: any) => { |   settingsManager.onSettingsChange(async (settings: any) => { | ||||||
|  |     if ( | ||||||
|  |       !peertube || | ||||||
|  |       peertube.username != settings["admin-name"] || | ||||||
|  |       peertube.password != settings["admin-password"] | ||||||
|  |     ) | ||||||
|  |       apiRequestInitializer({ | ||||||
|  |         domainName: peertubeHelpers.config.getWebserverUrl(), | ||||||
|  |         username: settings["admin-name"], | ||||||
|  |         password: settings["admin-password"], | ||||||
|  |       }); | ||||||
|  |  | ||||||
|     await addListeners(settings["ytb-urls"]); |     await addListeners(settings["ytb-urls"]); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -64,13 +93,31 @@ async function register({ | |||||||
|       JSON.stringify(entries) |       JSON.stringify(entries) | ||||||
|     ); |     ); | ||||||
|     for (const item of entries.items) |     for (const item of entries.items) | ||||||
|       await peertube.uploadFromUrl({ |       if (peertube) | ||||||
|         channelId: datas.channelId, |         await peertube.uploadFromUrl({ | ||||||
|         targetUrl: item.link, |           channelId: datas.channelId, | ||||||
|       }); |           targetUrl: item.link, | ||||||
|  |         }); | ||||||
|  |       else { | ||||||
|  |         logger.warn("Bad credential provides. New entries Skipped."); | ||||||
|  |       } | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function apiRequestInitializer(data: PeerTubeRequester.Config) { | ||||||
|  |   peertube = new PeerTubeRequester(data); | ||||||
|  |  | ||||||
|  |   try { | ||||||
|  |     await peertube.requestAuthToken(); | ||||||
|  |     goodPeertubeCredential = true; | ||||||
|  |     logger.debug("credential ok"); | ||||||
|  |   } catch (error) { | ||||||
|  |     logger.warn("Error during the credential validation : " + error); | ||||||
|  |     peertube = undefined; | ||||||
|  |     goodPeertubeCredential = false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| async function addListeners(listenerInput: string) { | async function addListeners(listenerInput: string) { | ||||||
|   let listeners: ListenerData[]; |   let listeners: ListenerData[]; | ||||||
|   try { |   try { | ||||||
| @@ -96,9 +143,9 @@ async function addListeners(listenerInput: string) { | |||||||
|   myManager.stopAll(); |   myManager.stopAll(); | ||||||
|   await myManager.saveOverride(listeners); |   await myManager.saveOverride(listeners); | ||||||
|  |  | ||||||
|   if (logger) logger.warn("Configuration changed: " + listenerInput); |   if (logger) logger.debug("Configuration changed: " + listenerInput); | ||||||
|  |  | ||||||
|   myManager.startAll(); |   if (goodPeertubeCredential) myManager.startAll(); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function unregister() { | async function unregister() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user