Compare commits
	
		
			6 Commits
		
	
	
		
			archive/te
			...
			archive/va
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ae195d9170 | ||
| 
						 | 
					f579afab16 | ||
| 
						 | 
					41098d09a7 | ||
| b2b04df23b | |||
| 51126e7f0f | |||
| 8f8f0c3cb0 | 
@@ -1,9 +1,6 @@
 | 
			
		||||
// import { ImplementableApi } from './implementableApi';
 | 
			
		||||
// Api request lib
 | 
			
		||||
import fetch, { FetchError, Headers } from "node-fetch";
 | 
			
		||||
import { URL, URLSearchParams } from "url";
 | 
			
		||||
import FormData from "form-data";
 | 
			
		||||
// import dedent from "ts-dedent";
 | 
			
		||||
 | 
			
		||||
namespace PeerTubeRequester {
 | 
			
		||||
  export type Config = {
 | 
			
		||||
@@ -19,22 +16,6 @@ type UploadInstruction = {
 | 
			
		||||
  targetUrl: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type ClientToken = {
 | 
			
		||||
  client_id: string;
 | 
			
		||||
  client_secret: string;
 | 
			
		||||
  grant_type: "password";
 | 
			
		||||
  response_type: "code";
 | 
			
		||||
  username: string;
 | 
			
		||||
  password: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type UserToken = {
 | 
			
		||||
  access_token: string;
 | 
			
		||||
  token_type: string;
 | 
			
		||||
  expires_in: string;
 | 
			
		||||
  refresh_token: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class PeerTubeRequester {
 | 
			
		||||
  readonly domain_name: URL;
 | 
			
		||||
  readonly username: string;
 | 
			
		||||
@@ -46,7 +27,7 @@ class PeerTubeRequester {
 | 
			
		||||
    this.password = config.password;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async apiRequest(message: UploadInstruction): Promise<void> {
 | 
			
		||||
  private async requestAuthToken(): Promise<any> {
 | 
			
		||||
    let response = await fetch(
 | 
			
		||||
      new URL(`/api/v1/oauth-clients/local`, this.domain_name)
 | 
			
		||||
    );
 | 
			
		||||
@@ -74,15 +55,18 @@ class PeerTubeRequester {
 | 
			
		||||
    if (!response.ok) {
 | 
			
		||||
      throw new Error(response.statusText); // CRASH
 | 
			
		||||
    }
 | 
			
		||||
    const { access_token } = await response.json();
 | 
			
		||||
    const { access_token: accessToken } = await response.json();
 | 
			
		||||
    return accessToken;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // Upload
 | 
			
		||||
  async uploadFromUrl(message: UploadInstruction): Promise<void> {
 | 
			
		||||
    const accessToken = await this.requestAuthToken();
 | 
			
		||||
    const myUploadForm = new URLSearchParams();
 | 
			
		||||
    const myHeader = new Headers();
 | 
			
		||||
    myHeader.append("Authorization", `Bearer ${access_token}`);
 | 
			
		||||
    myHeader.append("Authorization", `Bearer ${accessToken}`);
 | 
			
		||||
    for (const key in message) myUploadForm.append(key, message[key]);
 | 
			
		||||
 | 
			
		||||
    response = await fetch(
 | 
			
		||||
    const response = await fetch(
 | 
			
		||||
      new URL(`/api/v1/videos/imports`, this.domain_name),
 | 
			
		||||
      {
 | 
			
		||||
        method: "post",
 | 
			
		||||
@@ -95,9 +79,9 @@ class PeerTubeRequester {
 | 
			
		||||
      switch (response.status) {
 | 
			
		||||
        case 400:
 | 
			
		||||
          throw new Error(
 | 
			
		||||
            `Your target URL was not accepted by the API.\
 | 
			
		||||
                        Actualy it's : ${message.targetUrl}
 | 
			
		||||
                        ${response.statusText}`
 | 
			
		||||
            `Bad or malformed request. Probably because your target URL (from Youtube?) was not accepted by the API.\
 | 
			
		||||
                        The target URL you attempted to pass: ${message.targetUrl}.
 | 
			
		||||
                        Response from the server: ${response.statusText}`
 | 
			
		||||
          );
 | 
			
		||||
          break;
 | 
			
		||||
        case 403:
 | 
			
		||||
@@ -105,15 +89,15 @@ class PeerTubeRequester {
 | 
			
		||||
          break;
 | 
			
		||||
        case 409:
 | 
			
		||||
          throw new Error(
 | 
			
		||||
            `Oops, your instance had not allowed the HTTPS import.\
 | 
			
		||||
            `Oops, your instance did not allowed the HTTPS import.\
 | 
			
		||||
                        Contact your administrator.
 | 
			
		||||
                        ${response.statusText}`
 | 
			
		||||
          );
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          throw new Error(
 | 
			
		||||
            `Oh, you resolved an undocumented issues.\
 | 
			
		||||
                        Please report this on the git if you have the time.
 | 
			
		||||
            `Oh, you encountered an undocumented issues.\
 | 
			
		||||
                        Please create an issue to the plugin project.
 | 
			
		||||
                        ERROR: ${response.statusText}`
 | 
			
		||||
          );
 | 
			
		||||
          break;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										34
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,15 +1,15 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "peertube-plugin-auto-import-ytb",
 | 
			
		||||
  "version": "0.0.2",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "lockfileVersion": 2,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "packages": {
 | 
			
		||||
    "": {
 | 
			
		||||
      "version": "0.0.2",
 | 
			
		||||
      "version": "0.0.1",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/node-fetch": "^2.5.11",
 | 
			
		||||
        "form-data": "^4.0.0",
 | 
			
		||||
        "listener-rss-agregator": "git+https://zeteo.me/gitea/Outils-PeerTube/listener-rss-agregators#1b36afbb34",
 | 
			
		||||
        "listener-rss-aggregator": "^0.0.5",
 | 
			
		||||
        "node-fetch": "^2.6.1"
 | 
			
		||||
      },
 | 
			
		||||
      "devDependencies": {
 | 
			
		||||
@@ -398,11 +398,10 @@
 | 
			
		||||
        "rss-parser": "^3.11.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/listener-rss-agregator": {
 | 
			
		||||
      "version": "0.0.3",
 | 
			
		||||
      "resolved": "git+https://zeteo.me/gitea/Outils-PeerTube/listener-rss-agregators#1b36afbb344112c3827b5bcea92e1cc60bd8cf6a",
 | 
			
		||||
      "hasInstallScript": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
    "node_modules/listener-rss-aggregator": {
 | 
			
		||||
      "version": "0.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/listener-rss-aggregator/-/listener-rss-aggregator-0.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-0QE7kkzurjsWr4gNAJ4X+C7UFSyaVuYq2mKYXZ3shvyj81kULpBgFZSg/70MZkUoqixgWQ5P8oxyztRDOP78tw==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@databases/sqlite": "^3.0.0",
 | 
			
		||||
        "listener-rss": "^0.0.3"
 | 
			
		||||
@@ -799,9 +798,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/tar": {
 | 
			
		||||
      "version": "4.4.13",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
 | 
			
		||||
      "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
 | 
			
		||||
      "version": "4.4.14",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.14.tgz",
 | 
			
		||||
      "integrity": "sha512-ouN3XcSWYOAHmXZ+P4NEFJvqXL50To9OZBSQNNP30vBUFJFZZ0PLX15fnwupv6azfxMUfUDUr2fhYw4zGAEPcg==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "chownr": "^1.1.1",
 | 
			
		||||
        "fs-minipass": "^1.2.5",
 | 
			
		||||
@@ -1270,9 +1269,10 @@
 | 
			
		||||
        "rss-parser": "^3.11.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "listener-rss-agregator": {
 | 
			
		||||
      "version": "git+https://zeteo.me/gitea/Outils-PeerTube/listener-rss-agregators#1b36afbb344112c3827b5bcea92e1cc60bd8cf6a",
 | 
			
		||||
      "from": "listener-rss-agregator@git+https://zeteo.me/gitea/Outils-PeerTube/listener-rss-agregators#1b36afbb34",
 | 
			
		||||
    "listener-rss-aggregator": {
 | 
			
		||||
      "version": "0.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/listener-rss-aggregator/-/listener-rss-aggregator-0.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-0QE7kkzurjsWr4gNAJ4X+C7UFSyaVuYq2mKYXZ3shvyj81kULpBgFZSg/70MZkUoqixgWQ5P8oxyztRDOP78tw==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@databases/sqlite": "^3.0.0",
 | 
			
		||||
        "listener-rss": "^0.0.3"
 | 
			
		||||
@@ -1604,9 +1604,9 @@
 | 
			
		||||
      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
 | 
			
		||||
    },
 | 
			
		||||
    "tar": {
 | 
			
		||||
      "version": "4.4.13",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
 | 
			
		||||
      "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
 | 
			
		||||
      "version": "4.4.14",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.14.tgz",
 | 
			
		||||
      "integrity": "sha512-ouN3XcSWYOAHmXZ+P4NEFJvqXL50To9OZBSQNNP30vBUFJFZZ0PLX15fnwupv6azfxMUfUDUr2fhYw4zGAEPcg==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "chownr": "^1.1.1",
 | 
			
		||||
        "fs-minipass": "^1.2.5",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "peertube-plugin-auto-import-ytb",
 | 
			
		||||
  "description": "PeerTube plugin quickstart",
 | 
			
		||||
  "version": "0.0.2",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "author": "AmauryJOLY",
 | 
			
		||||
  "bugs": "https://framagit.org/framasoft/peertube/peertube-plugin-quickstart/issues",
 | 
			
		||||
  "clientScripts": [],
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@types/node-fetch": "^2.5.11",
 | 
			
		||||
    "form-data": "^4.0.0",
 | 
			
		||||
    "listener-rss-agregator": "git+https://zeteo.me/gitea/Outils-PeerTube/listener-rss-agregators#1b36afbb34",
 | 
			
		||||
    "listener-rss-aggregator": "^0.0.5",
 | 
			
		||||
    "node-fetch": "^2.6.1"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										224
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										224
									
								
								src/main.ts
									
									
									
									
									
								
							@@ -1,113 +1,111 @@
 | 
			
		||||
import { ListenerRssAggregator } from "listener-rss-agregator";
 | 
			
		||||
import { ListenerRss } from "listener-rss";
 | 
			
		||||
import { PeerTubeRequester } from "../lib/peertubeRequester";
 | 
			
		||||
 | 
			
		||||
type ListenerData = ListenerRss.Config & {
 | 
			
		||||
  address: string;
 | 
			
		||||
  channelId: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let myManager: ListenerRssAggregator;
 | 
			
		||||
let listenersDataBinding = new Map<string, ListenerData>();
 | 
			
		||||
let logger: any;
 | 
			
		||||
let peertube: PeerTubeRequester;
 | 
			
		||||
 | 
			
		||||
import * as path from "path";
 | 
			
		||||
import fs from "fs";
 | 
			
		||||
 | 
			
		||||
async function register({
 | 
			
		||||
  registerSetting,
 | 
			
		||||
  settingsManager,
 | 
			
		||||
  peertubeHelpers,
 | 
			
		||||
}: any) {
 | 
			
		||||
  const basePath = peertubeHelpers.plugin.getDataDirectoryPath();
 | 
			
		||||
  logger = peertubeHelpers.logger;
 | 
			
		||||
 | 
			
		||||
  registerSetting({
 | 
			
		||||
    name: "ytb-urls",
 | 
			
		||||
    label: "liste des urls youtube a auto-importer",
 | 
			
		||||
    type: "input-textarea",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  logger.warn("setting register");
 | 
			
		||||
  fs.appendFileSync(path.join(basePath, "/storage.bd"), "");
 | 
			
		||||
 | 
			
		||||
  const configAggregator = await ListenerRssAggregator.instantiateAggregator(
 | 
			
		||||
    path.join(basePath, "/storage.bd")
 | 
			
		||||
  );
 | 
			
		||||
  myManager = new ListenerRssAggregator(configAggregator);
 | 
			
		||||
 | 
			
		||||
  peertube = new PeerTubeRequester({
 | 
			
		||||
    domain_name: "http://localhost:9000",
 | 
			
		||||
    username: "root",
 | 
			
		||||
    password: "test",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  logger.warn("Aggregator created");
 | 
			
		||||
 | 
			
		||||
  const inputs = await settingsManager.getSetting("ytb-urls");
 | 
			
		||||
  if (inputs) await addListeners(inputs);
 | 
			
		||||
 | 
			
		||||
  logger.warn("Config loaded");
 | 
			
		||||
 | 
			
		||||
  settingsManager.onSettingsChange(async (settings: any) => {
 | 
			
		||||
    await addListeners(settings["ytb-urls"]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  myManager.on("newEntries", (entries: any) => {
 | 
			
		||||
    const datas = listenersDataBinding.get(entries.addressListener);
 | 
			
		||||
    if (!datas) return;
 | 
			
		||||
 | 
			
		||||
    logger.warn(
 | 
			
		||||
      "Nouvelles entrées détéctées: " +
 | 
			
		||||
        JSON.stringify(entries) +
 | 
			
		||||
        " de " +
 | 
			
		||||
        datas.channelId
 | 
			
		||||
    );
 | 
			
		||||
    for (const item of entries.items)
 | 
			
		||||
      peertube.apiRequest({
 | 
			
		||||
        channelId: datas.channelId,
 | 
			
		||||
        targetUrl: item.link,
 | 
			
		||||
      });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function addListeners(listenerInput: string) {
 | 
			
		||||
  let listeners: ListenerData[];
 | 
			
		||||
  try {
 | 
			
		||||
    listeners = JSON.parse(listenerInput);
 | 
			
		||||
  } catch {
 | 
			
		||||
    logger.warn("Erreur: malformé");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  let newListeners = listeners.filter(
 | 
			
		||||
    (item) => !listenersDataBinding.has(item.address)
 | 
			
		||||
  );
 | 
			
		||||
  let removedUrls = Array.from(listenersDataBinding.keys()).filter(
 | 
			
		||||
    (url) => !listeners.some((listener) => listener.address === url)
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  for (const newItem of newListeners) {
 | 
			
		||||
    listenersDataBinding.set(newItem.address, newItem);
 | 
			
		||||
  }
 | 
			
		||||
  for (const removedUrl of removedUrls) {
 | 
			
		||||
    listenersDataBinding.delete(removedUrl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  myManager.stopAll();
 | 
			
		||||
  await myManager.saveOverride(listeners);
 | 
			
		||||
 | 
			
		||||
  if (logger) logger.warn("Configuration modifiée: " + listenerInput);
 | 
			
		||||
 | 
			
		||||
  myManager.startAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function unregister() {
 | 
			
		||||
  myManager.stopAll();
 | 
			
		||||
  return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  register,
 | 
			
		||||
  unregister,
 | 
			
		||||
};
 | 
			
		||||
import { ListenerRssAggregator } from "listener-rss-aggregator";
 | 
			
		||||
import { ListenerRss } from "listener-rss";
 | 
			
		||||
import { PeerTubeRequester } from "../lib/peertubeRequester";
 | 
			
		||||
 | 
			
		||||
type ListenerData = ListenerRss.Config & {
 | 
			
		||||
  address: string;
 | 
			
		||||
  channelId: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let myManager: ListenerRssAggregator;
 | 
			
		||||
let listenersDataBinding = new Map<string, ListenerData>();
 | 
			
		||||
let logger: any;
 | 
			
		||||
let peertube: PeerTubeRequester;
 | 
			
		||||
 | 
			
		||||
import * as path from "path";
 | 
			
		||||
import fs from "fs";
 | 
			
		||||
 | 
			
		||||
async function register({
 | 
			
		||||
  registerSetting,
 | 
			
		||||
  settingsManager,
 | 
			
		||||
  peertubeHelpers,
 | 
			
		||||
}: any) {
 | 
			
		||||
  const basePath = peertubeHelpers.plugin.getDataDirectoryPath();
 | 
			
		||||
  logger = peertubeHelpers.logger;
 | 
			
		||||
 | 
			
		||||
  registerSetting({
 | 
			
		||||
    name: "ytb-urls",
 | 
			
		||||
    label: "URL list of Youtube channel to synchronize",
 | 
			
		||||
    type: "input-textarea",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  logger.debug("setting register");
 | 
			
		||||
  fs.appendFileSync(path.join(basePath, "/storage.bd"), "");
 | 
			
		||||
 | 
			
		||||
  const configAggregator = await ListenerRssAggregator.instantiateAggregator(
 | 
			
		||||
    path.join(basePath, "/storage.bd")
 | 
			
		||||
  );
 | 
			
		||||
  myManager = new ListenerRssAggregator(configAggregator);
 | 
			
		||||
 | 
			
		||||
  peertube = new PeerTubeRequester({
 | 
			
		||||
    domain_name: "http://localhost:9000",
 | 
			
		||||
    username: "root",
 | 
			
		||||
    password: "test",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  logger.debug("Aggregator created");
 | 
			
		||||
 | 
			
		||||
  const inputs = await settingsManager.getSetting("ytb-urls");
 | 
			
		||||
  if (inputs) await addListeners(inputs);
 | 
			
		||||
 | 
			
		||||
  logger.debug("Config loaded");
 | 
			
		||||
 | 
			
		||||
  settingsManager.onSettingsChange(async (settings: any) => {
 | 
			
		||||
    await addListeners(settings["ytb-urls"]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  myManager.on("newEntries", async (entries: any) => {
 | 
			
		||||
    const datas = listenersDataBinding.get(entries.addressListener);
 | 
			
		||||
    if (!datas) return;
 | 
			
		||||
 | 
			
		||||
    logger.debug(
 | 
			
		||||
      "New entries detected from channel #%i: %s",
 | 
			
		||||
      datas.channelId,
 | 
			
		||||
      JSON.stringify(entries)
 | 
			
		||||
    );
 | 
			
		||||
    for (const item of entries.items)
 | 
			
		||||
      await peertube.uploadFromUrl({
 | 
			
		||||
        channelId: datas.channelId,
 | 
			
		||||
        targetUrl: item.link,
 | 
			
		||||
      });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function addListeners(listenerInput: string) {
 | 
			
		||||
  let listeners: ListenerData[];
 | 
			
		||||
  try {
 | 
			
		||||
    listeners = JSON.parse(listenerInput);
 | 
			
		||||
  } catch {
 | 
			
		||||
    logger.error("Malformed URL");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  let newListeners = listeners.filter(
 | 
			
		||||
    (item) => !listenersDataBinding.has(item.address)
 | 
			
		||||
  );
 | 
			
		||||
  let removedUrls = Array.from(listenersDataBinding.keys()).filter(
 | 
			
		||||
    (url) => !listeners.some((listener) => listener.address === url)
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  for (const newItem of newListeners) {
 | 
			
		||||
    listenersDataBinding.set(newItem.address, newItem);
 | 
			
		||||
  }
 | 
			
		||||
  for (const removedUrl of removedUrls) {
 | 
			
		||||
    listenersDataBinding.delete(removedUrl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  myManager.stopAll();
 | 
			
		||||
  await myManager.saveOverride(listeners);
 | 
			
		||||
 | 
			
		||||
  if (logger) logger.warn("Configuration changed: " + listenerInput);
 | 
			
		||||
 | 
			
		||||
  myManager.startAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function unregister() {
 | 
			
		||||
  myManager.stopAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  register,
 | 
			
		||||
  unregister,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user