Add auto block videos plugin
This commit is contained in:
		
							
								
								
									
										60
									
								
								peertube-plugin-auto-block-videos/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								peertube-plugin-auto-block-videos/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| # Auto block videos plugin for PeerTube | ||||
|  | ||||
| Auto block videos based on public blocklists. | ||||
|  | ||||
| ## Block lists | ||||
|  | ||||
| **Add your public list here** | ||||
|  | ||||
| ## Blocklist URL format | ||||
|  | ||||
| This plugin expects the following JSON format from public blocklists: | ||||
|  | ||||
| ``` | ||||
| { | ||||
|   data: { | ||||
|     value: string | ||||
|     action?: 'add' | 'remove' // Default is 'add' | ||||
|     updatedAt?: string // ISO 8601 | ||||
|   }[] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| For example: | ||||
|  | ||||
| ``` | ||||
| { | ||||
|   data: [ | ||||
|     { | ||||
|       value: 'https://framatube.org/videos/watch/37938234-ddf2-46d7-8967-8ac84820d5cd' | ||||
|     }, | ||||
|     { | ||||
|       value: 'https://peertube.cpy.re/videos/watch/f78a97f8-a142-4ce1-a5bd-154bf9386504', | ||||
|       updatedAt: '2020-05-07T14:42:48.954Z' | ||||
|     } | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| This plugin does not apply a diff, so if you want to remove an entity from the blocklist, add `action: 'remove'` to the object. | ||||
|  | ||||
| For example, to revert `https://peertube.cpy.re/videos/watch/f78a97f8-a142-4ce1-a5bd-154bf9386504` from the blocklist, update the JSON: | ||||
|  | ||||
| ``` | ||||
| { | ||||
|   data: [ | ||||
|     { | ||||
|       value: 'https://peertube.cpy.re/videos/watch/f78a97f8-a142-4ce1-a5bd-154bf9386504', | ||||
|       action: 'remove' | ||||
|     }, | ||||
|     { | ||||
|       value: 'https://framatube.org/videos/watch/37938234-ddf2-46d7-8967-8ac84820d5cd' | ||||
|     } | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The purpose of the `updatedAt` field is to not override admin blocks/unblocks: | ||||
|  * Plugin auto block video A with an `updatedAt: '2020-05-07T14:42:48.954Z'` | ||||
|  * Admin thinks this video is fine so it unblocks video A | ||||
|  * On another check, the plugin won't re-block the account A because the `updatedAt` is before the last check | ||||
							
								
								
									
										181
									
								
								peertube-plugin-auto-block-videos/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								peertube-plugin-auto-block-videos/main.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,181 @@ | ||||
| const simpleGet = require('simple-get') | ||||
|  | ||||
| const store = { | ||||
|   urls: [], | ||||
|   checkIntervalSeconds: null, | ||||
|   alreadyAdded: new Set(), | ||||
|   alreadyRemoved: new Set(), | ||||
|   timeout: null | ||||
| } | ||||
|  | ||||
| async function register ({ | ||||
|   settingsManager, | ||||
|   storageManager, | ||||
|   peertubeHelpers, | ||||
|   registerSetting | ||||
| }) { | ||||
|   const { logger } = peertubeHelpers | ||||
|  | ||||
|   registerSetting({ | ||||
|     name: 'blocklist-urls', | ||||
|     label: 'Blocklist URLs (one per line)', | ||||
|     type: 'input-textarea', | ||||
|     private: true | ||||
|   }) | ||||
|  | ||||
|   registerSetting({ | ||||
|     name: 'check-seconds-interval', | ||||
|     label: 'Blocklist check frequency (seconds)', | ||||
|     type: 'input', | ||||
|     private: true, | ||||
|     default: 3600 // 1 Hour | ||||
|   }) | ||||
|  | ||||
|   const settings = await settingsManager.getSettings([ 'check-seconds-interval', 'blocklist-urls' ]) | ||||
|  | ||||
|   await load(peertubeHelpers, storageManager, settings['blocklist-urls'], settings['check-seconds-interval']) | ||||
|  | ||||
|   settingsManager.onSettingsChange(settings => { | ||||
|     load(peertubeHelpers, storageManager, settings['blocklist-urls'], settings['check-seconds-interval']) | ||||
|       .catch(err => logger.error('Cannot load auto block videos plugin.', { err })) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| async function unregister () { | ||||
|   return | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|   register, | ||||
|   unregister | ||||
| } | ||||
|  | ||||
| // ############################################################################ | ||||
|  | ||||
| async function load (peertubeHelpers, storageManager, blocklistUrls, checkIntervalSeconds) { | ||||
|   const { logger } = peertubeHelpers | ||||
|  | ||||
|   if (store.timeout) clearTimeout(store.timeout) | ||||
|  | ||||
|   store.checkIntervalSeconds = checkIntervalSeconds | ||||
|  | ||||
|   store.urls = (blocklistUrls || '').split('\n') | ||||
|                                     .filter(url => !!url) | ||||
|  | ||||
|   if (store.urls.length === 0) { | ||||
|     logger.info('Do not load auto block videos plugin because of empty blocklist URLs.') | ||||
|     return | ||||
|   } | ||||
|  | ||||
|   logger.info('Loaded %d blocklist URLs for auto block videos plugin.', store.urls.length, { urls: store.urls }) | ||||
|  | ||||
|   runLater(peertubeHelpers, storageManager) | ||||
| } | ||||
|  | ||||
| async function runCheck (peertubeHelpers, storageManager) { | ||||
|   const { logger } = peertubeHelpers | ||||
|  | ||||
|   if (store.urls.length === 0) return runLater(peertubeHelpers, storageManager) | ||||
|  | ||||
|   let lastChecks = await storageManager.getData('last-checks') | ||||
|   if (!lastChecks) lastChecks = {} | ||||
|  | ||||
|   const newLastCheck = {} | ||||
|  | ||||
|   for (const url of store.urls) { | ||||
|     try { | ||||
|       const { data } = await get(url) | ||||
|       newLastCheck[url] = new Date().toISOString() | ||||
|  | ||||
|       const lastCheckTime = lastChecks[url] | ||||
|         ? new Date(lastChecks[url]).getTime() | ||||
|         : 0 | ||||
|  | ||||
|       if (Array.isArray(data.data) === false) { | ||||
|         logger.error('JSON response is not valid from %s.', { data }) | ||||
|         continue | ||||
|       } | ||||
|  | ||||
|       for (const entity of data.data) { | ||||
|         if (!entity.value) { | ||||
|           logger.error('JSON entity is not valid.', { entity }) | ||||
|           continue | ||||
|         } | ||||
|  | ||||
|         // We already checked this entity? | ||||
|         if (entity.updatedAt) { | ||||
|           const updatedAtTime = new Date(entity.updatedAt).getTime() | ||||
|  | ||||
|           if (updatedAtTime < lastCheckTime) continue | ||||
|         } | ||||
|  | ||||
|         if (entity.action === 'remove') await removeEntity(peertubeHelpers, entity.value) | ||||
|         else await addEntity(peertubeHelpers, entity.value) | ||||
|       } | ||||
|     } catch (err) { | ||||
|       logger.warn('Cannot auto block videos from %s.', url, { err }) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   await storageManager.storeData('last-checks', newLastCheck) | ||||
|  | ||||
|   runLater(peertubeHelpers, storageManager) | ||||
| } | ||||
|  | ||||
| function runLater (peertubeHelpers, storageManager) { | ||||
|   const { logger } = peertubeHelpers | ||||
|  | ||||
|   logger.debug('Will run auto videos block check in %d seconds.', store.checkIntervalSeconds) | ||||
|  | ||||
|   store.timeout = setTimeout(() => { | ||||
|     runCheck(peertubeHelpers, storageManager) | ||||
|   }, store.checkIntervalSeconds * 1000) | ||||
| } | ||||
|  | ||||
| function get (url) { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     simpleGet.concat({ url, method: 'GET', json: true }, function (err, res, data) { | ||||
|       if (err) return reject(err) | ||||
|  | ||||
|       return resolve({ res, data }) | ||||
|     }) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| async function addEntity (peertubeHelpers, value) { | ||||
|   const { moderation, videos, logger } = peertubeHelpers | ||||
|  | ||||
|   if (store.alreadyAdded.has(value)) return | ||||
|  | ||||
|   store.alreadyRemoved.delete(value) | ||||
|   store.alreadyAdded.add(value) | ||||
|  | ||||
|   const video = await videos.loadByUrl(value) | ||||
|   if (!video) return | ||||
|  | ||||
|   if (video.remote !== true) { | ||||
|     logger.info('Do not auto block our own video %s.', value) | ||||
|     return | ||||
|   } | ||||
|  | ||||
|   logger.info('Auto block video %s from blocklist.', value) | ||||
|  | ||||
|   const reason = 'Automatically blocked from auto block plugin.' | ||||
|   return moderation.blacklistVideo({ videoIdOrUUID: video.id, createOptions: { reason } }) | ||||
| } | ||||
|  | ||||
| async function removeEntity (peertubeHelpers, value) { | ||||
|   const { moderation, logger, videos } = peertubeHelpers | ||||
|  | ||||
|   if (store.alreadyRemoved.has(value)) return | ||||
|  | ||||
|   store.alreadyAdded.delete(value) | ||||
|   store.alreadyRemoved.add(value) | ||||
|  | ||||
|   const video = await videos.loadByUrl(value) | ||||
|   if (!video) return | ||||
|  | ||||
|   logger.info('Auto removing video %s from blocklist.', value) | ||||
|  | ||||
|   return moderation.unblacklistVideo({ videoIdOrUUID: video.id }) | ||||
| } | ||||
							
								
								
									
										49
									
								
								peertube-plugin-auto-block-videos/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								peertube-plugin-auto-block-videos/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| { | ||||
|   "name": "peertube-plugin-auto-block-videos", | ||||
|   "version": "0.0.1", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
|   "dependencies": { | ||||
|     "decompress-response": { | ||||
|       "version": "4.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", | ||||
|       "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", | ||||
|       "requires": { | ||||
|         "mimic-response": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "mimic-response": { | ||||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", | ||||
|       "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" | ||||
|     }, | ||||
|     "once": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | ||||
|       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", | ||||
|       "requires": { | ||||
|         "wrappy": "1" | ||||
|       } | ||||
|     }, | ||||
|     "simple-concat": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", | ||||
|       "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" | ||||
|     }, | ||||
|     "simple-get": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", | ||||
|       "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", | ||||
|       "requires": { | ||||
|         "decompress-response": "^4.2.0", | ||||
|         "once": "^1.3.1", | ||||
|         "simple-concat": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "wrappy": { | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | ||||
|       "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										23
									
								
								peertube-plugin-auto-block-videos/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								peertube-plugin-auto-block-videos/package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| { | ||||
|   "name": "peertube-plugin-auto-block-videos", | ||||
|   "version": "0.0.1", | ||||
|   "description": "Auto block videos plugin for PeerTube", | ||||
|   "engine": { | ||||
|     "peertube": ">=2.2.0" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "peertube", | ||||
|     "plugin" | ||||
|   ], | ||||
|   "homepage": "https://framagit.org/framasoft/peertube/official-plugins/tree/master/peertube-plugin-auto-block-videos", | ||||
|   "author": "Chocobozzz", | ||||
|   "bugs": "https://framagit.org/framasoft/peertube/official-plugins/issues", | ||||
|   "library": "./main.js", | ||||
|   "staticDirs": {}, | ||||
|   "css": [], | ||||
|   "clientScripts": [], | ||||
|   "translations": {}, | ||||
|   "dependencies": { | ||||
|     "simple-get": "^3.1.0" | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,10 @@ | ||||
| { | ||||
|   "data": [ | ||||
|     { | ||||
|       "value": "peertube.cpy.re" | ||||
|     }, | ||||
|     { | ||||
|       "value": "peertube3.cpy.re" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
		Reference in New Issue
	
	Block a user