Compare commits

...

24 Commits

Author SHA1 Message Date
6dadf326ac update meta-data inside package.json 2021-07-30 13:11:11 +02:00
809803a194 update README.md 2021-07-30 13:10:34 +02:00
2c6df73d02 Fix some refactiring error. And Add a way to insert admin credentials 2021-07-30 12:40:24 +02:00
Amaury
6407c1b072 refactor names inside main.ts 2021-07-28 14:22:04 +02:00
Amaury
b9d99891db Remove useless imports 2021-07-28 14:21:51 +02:00
Amaury
48b73a89bc refactor names inside peertubeRequester.ts 2021-07-28 14:21:51 +02:00
Amaury
82f4a3e6ec added expected package in package.json and package-lock.json 2021-07-28 13:25:19 +02:00
df0e311dbc Merge pull request 'Various improvements' (#3) from various-improvements into master
Reviewed-on: Outils-PeerTube/peertube-plugin-auto-import-ytb#3
2021-07-27 18:39:48 +02:00
Amaury
ae195d9170 Fix b2b04df23b
requestAuthToken was set to async but he wasn't waited for his usage.
2021-07-27 18:33:53 +02:00
Amaury
f579afab16 updated to the latest version of listner-rss-aggregator 2021-07-27 16:14:13 +02:00
Amaury
41098d09a7 Minor refactor to publish 2021-07-26 16:07:39 +02:00
b2b04df23b Adapt main.ts to use PeerTubeRequester.prototype.uploadFromUrl 2021-07-25 16:59:42 +02:00
51126e7f0f Split PeertubeRequester main function into 2 2021-07-25 16:56:25 +02:00
8f8f0c3cb0 Translate labels and log messages 2021-07-25 16:38:19 +02:00
Amaury
9597cddc80 Ca marche pas trop mal 2021-07-12 17:02:39 +02:00
Amaury
81f540e29d Ajout peertubeRequester 2021-07-09 14:26:23 +02:00
Amaury
4f6587e1f6 merge 2021-07-09 12:18:08 +02:00
Amaury
ce19792a28 Merge remote-tracking branch 'origin/testing' into testing 2021-07-09 12:17:50 +02:00
Amaury
ea6adfc1fc refactor 2021-07-09 12:13:41 +02:00
Florent
db856aa6e2 Prettier 2021-07-06 16:01:06 +02:00
Amaury
afdd320056 rename prettierrc 2021-07-06 15:59:40 +02:00
Amaury
f26ac80aa5 adapted to listener-rss v 0.0.3 2021-07-06 15:32:47 +02:00
85d38f7939 Fix addListeners 2021-07-06 13:38:20 +02:00
Amaury
f21f752cbb . 2021-07-06 13:16:54 +02:00
9 changed files with 529 additions and 120 deletions

1
.prettierrc.json Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -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.

110
lib/peertubeRequester.ts Normal file
View File

@ -0,0 +1,110 @@
// Api request lib
import fetch, { Headers } from "node-fetch";
import { URL, URLSearchParams } from "url";
namespace PeerTubeRequester {
export type Config = {
domainName: string | URL;
username: string;
password: string;
};
}
type UploadInstruction = {
[key: string]: string;
channelId: string;
targetUrl: string;
};
class PeerTubeRequester {
readonly domainName: URL;
readonly username: string;
readonly password: string;
constructor(readonly config: PeerTubeRequester.Config) {
this.domainName = new URL("/", config.domainName);
this.username = config.username;
this.password = config.password;
}
async requestAuthToken(): Promise<any> {
let response = await fetch(
new URL(`/api/v1/oauth-clients/local`, this.domainName)
);
if (!response.ok) {
throw new Error("Cannot get client credentials : " + response.statusText); // CRASH
}
const { client_id: clientId, client_secret: clientSecret } =
await response.json();
const clientInfo: { [key: string]: string } = {
client_id: clientId,
client_secret: clientSecret,
grant_type: "password",
response_type: "code",
username: this.username,
password: this.password,
};
let myParams = new URLSearchParams();
for (const key in clientInfo) myParams.append(key, clientInfo[key]);
response = await fetch(new URL(`/api/v1/users/token`, this.domainName), {
method: "post",
body: myParams,
});
if (!response.ok) {
throw new Error("Cannot get access Token : " + response.statusText); // CRASH
}
const { access_token: accessToken } = await response.json();
return accessToken;
}
async uploadFromUrl(message: UploadInstruction): Promise<void> {
const accessToken = await this.requestAuthToken();
const myUploadForm = new URLSearchParams();
const myHeader = new Headers();
myHeader.append("Authorization", `Bearer ${accessToken}`);
for (const key in message) myUploadForm.append(key, message[key]);
const response = await fetch(
new URL("/api/v1/videos/imports", this.domainName),
{
method: "post",
headers: myHeader,
body: myUploadForm,
}
);
if (!response.ok) {
switch (response.status) {
case 400:
throw new Error(
`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:
throw new Error(response.statusText);
break;
case 409:
throw new Error(
`Oops, your instance did not allowed the HTTPS import.\
Contact your administrator.
${response.statusText}`
);
break;
default:
throw new Error(
`Oh, you encountered an undocumented issues.\
Please create an issue to the plugin project.
ERROR: ${response.statusText}`
);
break;
}
}
}
}
export { PeerTubeRequester };

275
package-lock.json generated
View File

@ -1,13 +1,17 @@
{
"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": {
"listener-rss-agregator": "0.0.2"
"@types/node-fetch": "^2.5.11",
"form-data": "^4.0.0",
"listener-rss": "^0.0.3",
"listener-rss-aggregator": "^0.0.5",
"node-fetch": "^2.6.1"
},
"devDependencies": {
"ts-node": "^10.0.0",
@ -69,9 +73,31 @@
"dev": true
},
"node_modules/@types/node": {
"version": "15.12.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz",
"integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg=="
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz",
"integrity": "sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA=="
},
"node_modules/@types/node-fetch": {
"version": "2.5.11",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.11.tgz",
"integrity": "sha512-2upCKaqVZETDRb8A2VTaRymqFBEgH8u6yr96b/u3+1uQEPDRo3mJLEiPk7vdXBHRtjwkjqzFYMJXrt0Z9QsYjQ==",
"dependencies": {
"@types/node": "*",
"form-data": "^3.0.0"
}
},
"node_modules/@types/node-fetch/node_modules/form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/@types/sqlite3": {
"version": "3.1.7",
@ -119,6 +145,11 @@
"resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz",
"integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -152,6 +183,17 @@
"node": ">=0.10.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -189,6 +231,14 @@
"node": ">=4.0.0"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@ -222,6 +272,19 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
@ -329,20 +392,20 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"node_modules/listener-rss": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/listener-rss/-/listener-rss-0.0.1.tgz",
"integrity": "sha512-ljH6FD4NMypkrZ9ZIMdW2YdAlm/Jer++zPI+1HTWK7BbhPJmUF3sSymqUqAjBcfH3xjt+fpYPqYgNYNM1fEYpA==",
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/listener-rss/-/listener-rss-0.0.3.tgz",
"integrity": "sha512-rccetOTwyyww/KDuaMX0EMjaGi+Jx+bojp18Ucxra6OeCfz2hC9FEasVNeENR096+ndOCS/rkKTJl+RD9rlAAQ==",
"dependencies": {
"rss-parser": "3.11.0"
"rss-parser": "^3.11.0"
}
},
"node_modules/listener-rss-agregator": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/listener-rss-agregator/-/listener-rss-agregator-0.0.2.tgz",
"integrity": "sha512-ATj4esXtHLThe1/wkJ/ukA9+pC9FwBCNZCbVv7Ywr1eIbxBR+AHR5090lzCQt3WJsBblpTTZMni+vHxmGjRR7Q==",
"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.1"
"listener-rss": "^0.0.3"
}
},
"node_modules/make-error": {
@ -351,6 +414,25 @@
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/mime-db": {
"version": "1.48.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.31",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
"dependencies": {
"mime-db": "1.48.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@ -406,9 +488,9 @@
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
},
"node_modules/needle": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz",
"integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.8.0.tgz",
"integrity": "sha512-ZTq6WYkN/3782H1393me3utVYdq2XyqNUFBsprEE3VMAT0+hP/cItpnITpqsY6ep2yeFE4Tqtqwc74VqUlUYtw==",
"dependencies": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
@ -421,6 +503,14 @@
"node": ">= 4.4.x"
}
},
"node_modules/node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"engines": {
"node": "4.x || >=6.0.0"
}
},
"node_modules/node-pre-gyp": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
@ -598,9 +688,9 @@
}
},
"node_modules/rss-parser": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.11.0.tgz",
"integrity": "sha512-oTLoYW+bNqNwkz8OpGinBU9s3As0sdczQjETIZFgyAdi7AopyhoVFGPIyFMYXXEY8hayKzD5CH+4CtmiPtJ89g==",
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.12.0.tgz",
"integrity": "sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==",
"dependencies": {
"entities": "^2.0.3",
"xml2js": "^0.4.19"
@ -709,9 +799,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",
@ -734,9 +824,9 @@
}
},
"node_modules/ts-node": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
"integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.1.0.tgz",
"integrity": "sha512-6szn3+J9WyG2hE+5W8e0ruZrzyk1uFLYye6IGMBadnOzDh8aP7t8CbFpsfCiEx2+wMixAhjFt7lOZC4+l+WbEA==",
"dev": true,
"dependencies": {
"@tsconfig/node10": "^1.0.7",
@ -761,8 +851,8 @@
"node": ">=12.0.0"
},
"peerDependencies": {
"@swc/core": ">=1.2.45",
"@swc/wasm": ">=1.2.45",
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
@ -776,9 +866,9 @@
}
},
"node_modules/typescript": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@ -897,9 +987,30 @@
"dev": true
},
"@types/node": {
"version": "15.12.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz",
"integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg=="
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz",
"integrity": "sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA=="
},
"@types/node-fetch": {
"version": "2.5.11",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.11.tgz",
"integrity": "sha512-2upCKaqVZETDRb8A2VTaRymqFBEgH8u6yr96b/u3+1uQEPDRo3mJLEiPk7vdXBHRtjwkjqzFYMJXrt0Z9QsYjQ==",
"requires": {
"@types/node": "*",
"form-data": "^3.0.0"
},
"dependencies": {
"form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
}
}
},
"@types/sqlite3": {
"version": "3.1.7",
@ -944,6 +1055,11 @@
"resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz",
"integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -974,6 +1090,14 @@
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -1008,6 +1132,11 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@ -1029,6 +1158,16 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
@ -1124,20 +1263,20 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"listener-rss": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/listener-rss/-/listener-rss-0.0.1.tgz",
"integrity": "sha512-ljH6FD4NMypkrZ9ZIMdW2YdAlm/Jer++zPI+1HTWK7BbhPJmUF3sSymqUqAjBcfH3xjt+fpYPqYgNYNM1fEYpA==",
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/listener-rss/-/listener-rss-0.0.3.tgz",
"integrity": "sha512-rccetOTwyyww/KDuaMX0EMjaGi+Jx+bojp18Ucxra6OeCfz2hC9FEasVNeENR096+ndOCS/rkKTJl+RD9rlAAQ==",
"requires": {
"rss-parser": "3.11.0"
"rss-parser": "^3.11.0"
}
},
"listener-rss-agregator": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/listener-rss-agregator/-/listener-rss-agregator-0.0.2.tgz",
"integrity": "sha512-ATj4esXtHLThe1/wkJ/ukA9+pC9FwBCNZCbVv7Ywr1eIbxBR+AHR5090lzCQt3WJsBblpTTZMni+vHxmGjRR7Q==",
"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.1"
"listener-rss": "^0.0.3"
}
},
"make-error": {
@ -1146,6 +1285,19 @@
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"mime-db": {
"version": "1.48.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
},
"mime-types": {
"version": "2.1.31",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
"requires": {
"mime-db": "1.48.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@ -1195,15 +1347,20 @@
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
},
"needle": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz",
"integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.8.0.tgz",
"integrity": "sha512-ZTq6WYkN/3782H1393me3utVYdq2XyqNUFBsprEE3VMAT0+hP/cItpnITpqsY6ep2yeFE4Tqtqwc74VqUlUYtw==",
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
}
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-pre-gyp": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
@ -1353,9 +1510,9 @@
}
},
"rss-parser": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.11.0.tgz",
"integrity": "sha512-oTLoYW+bNqNwkz8OpGinBU9s3As0sdczQjETIZFgyAdi7AopyhoVFGPIyFMYXXEY8hayKzD5CH+4CtmiPtJ89g==",
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.12.0.tgz",
"integrity": "sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==",
"requires": {
"entities": "^2.0.3",
"xml2js": "^0.4.19"
@ -1448,9 +1605,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",
@ -1470,9 +1627,9 @@
}
},
"ts-node": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
"integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.1.0.tgz",
"integrity": "sha512-6szn3+J9WyG2hE+5W8e0ruZrzyk1uFLYye6IGMBadnOzDh8aP7t8CbFpsfCiEx2+wMixAhjFt7lOZC4+l+WbEA==",
"dev": true,
"requires": {
"@tsconfig/node10": "^1.0.7",
@ -1488,9 +1645,9 @@
}
},
"typescript": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz",
"integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
"dev": true
},
"util-deprecate": {

View File

@ -1,9 +1,9 @@
{
"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.2",
"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": [],
"css": [],
"devDependencies": {
@ -13,24 +13,28 @@
"engine": {
"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": [
"peertube",
"plugin"
],
"library": "./dist/main.js",
"library": "./dist/src/main.js",
"files": [
"dist/",
"README.md"
],
"scripts": {
"buildAndDeploy": "npm run build && npm run deploy",
"predeploy": "npm run build",
"deploy": "bash ./scripts/deploy.sh",
"build": "tsc"
},
"staticDirs": {},
"translations": {},
"dependencies": {
"listener-rss-agregator": "0.0.2"
"@types/node-fetch": "^2.5.11",
"form-data": "^4.0.0",
"listener-rss-aggregator": "^0.0.5",
"listener-rss": "^0.0.3",
"node-fetch": "^2.6.1"
}
}

View File

@ -1,12 +1,13 @@
#/bin/bash
tmp_dir=$(mktemp -d)/peertube-plugin-auto-import-ytb
work_dir=$(pwd)
# echo $work_dir
# echo "${work_dir}"
mkdir $tmp_dir
mkdir "${tmp_dir}"
# echo "directory created"
cp "${work_dir}/dist" "${work_dir}/package.json" "${work_dir}/LICENSE" $tmp_dir -r
# echo "rsync --exclude-from=$work_dir.rsyncignore $work_dir $tmp_dir"
# echo "rsync done"
cd "../PeerTube"
cd "../PeerTube-cli"
node "./dist/server/tools/peertube.js" plugins install --path "${tmp_dir}"
# echo $tmp_dir

View File

@ -1,63 +1,158 @@
import { ManageListener } from 'listener-rss-agregator';
import { ListenerRssAggregator } from "listener-rss-aggregator";
import { ListenerRss } from "listener-rss";
import { PeerTubeRequester } from "../lib/peertubeRequester";
let myManager : ManageListener;
let bindistenerChannelId: {[key: string] : string} = {};
type ListenerData = ListenerRss.Config & {
address: string;
channelId: string;
};
import * as path from 'path';
let myManager: ListenerRssAggregator;
let listenersDataBinding = new Map<string, ListenerData>();
let logger: any;
let peertube: PeerTubeRequester | undefined = undefined;
let goodPeertubeCredential: boolean = false;
import * as path from "path";
import fs from "fs";
async function register({
registerSetting,
settingsManager,
registerSetting,
settingsManager,
peertubeHelpers,
}: any) {
registerSetting({
name: 'ytb-urls',
label: 'liste des urls youtube a auto-importer',
type: 'input-textarea'
})
const basePath = peertubeHelpers.plugin.getDataDirectoryPath();
myManager = new ManageListener(path.join(basePath, '/data/storage.bd'));
logger = peertubeHelpers.logger;
const inputs = await settingsManager.getSetting('ytb-urls');
registerSetting({
name: "ytb-urls",
label: "URL list of Youtube channel to synchronize",
type: "input-textarea",
});
addListeners(inputs);
registerSetting({
name: "admin-name",
label: "Admin Username",
type: "input",
});
settingsManager.onSettingsChange((settings: any) => {
myManager.stopAll();
myManager.save();
registerSetting({
name: "admin-password",
label: "Admin Password",
type: "input-password",
});
addListeners(settings['ytb-urls']);
})
logger.debug("setting register");
fs.appendFileSync(path.join(basePath, "/storage.bd"), "");
myManager.on('update', (entries: any) => {
// for (const item in entries.items)
// console.info(item.)
const configAggregator = await ListenerRssAggregator.instantiateAggregator(
path.join(basePath, "/storage.bd")
);
myManager = new ListenerRssAggregator(configAggregator);
})
logger.debug("Aggregator created");
const settingYtbUrls = await settingsManager.getSetting("ytb-urls");
if (settingYtbUrls) await addListeners(settingYtbUrls);
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) => {
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"]);
});
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)
if (peertube)
await peertube.uploadFromUrl({
channelId: datas.channelId,
targetUrl: item.link,
});
else {
logger.warn("Bad credential provides. New entries Skipped.");
}
});
}
function addListeners(listenerInput: any) {
for (const line in listenerInput.split('\n'))
if (!myManager.listenerArray.map((it: any) => it.address).includes(line)) // si ligne non présente
{
let splitted = line.split(':');
bindistenerChannelId[splitted[1]] = splitted[0];
myManager.registerListener({ address: splitted[0] });
}
async function apiRequestInitializer(data: PeerTubeRequester.Config) {
peertube = new PeerTubeRequester(data);
myManager.save();
myManager.startAll();
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) {
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.debug("Configuration changed: " + listenerInput);
if (goodPeertubeCredential) myManager.startAll();
}
async function unregister() {
myManager.stopAll();
myManager.save();
return
}
module.exports = {
register,
unregister
}
unregister,
};

View File

@ -4,8 +4,8 @@
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
@ -14,8 +14,8 @@
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist/", /* Redirect output structure to the directory. */
"rootDir": "./src/", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"outDir": "./dist/" /* Redirect output structure to the directory. */,
// "rootDir": "./src/", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
@ -25,7 +25,7 @@
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
@ -47,11 +47,14 @@
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
"rootDirs": [
"./src/",
"./lib/"
] /* List of root folders whose combined content represents the structure of the project at runtime. */,
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
@ -66,7 +69,7 @@
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}