| |
| |
| |
|
|
| const nsfwRoutes = [ |
| '141jav', |
| '141ppv', |
| '18comic', |
| '2048', |
| '7mmtv', |
| '8kcos', |
| '91porn', |
| '95mm', |
| 'abskoop', |
| 'asiantolick', |
| 'asmr-200', |
| 'booru', |
| 'chikubi', |
| 'chub', |
| 'civitai', |
| 'cool18', |
| 'coomer', |
| 'copymanga', |
| 'cosplaytele', |
| 'dlsite', |
| 'e-hentai', |
| 'ehentai', |
| 'everia', |
| 'fanbox', |
| 'fansly', |
| 'fantia', |
| 'freexcomic', |
| 'furaffinity', |
| 'gelbooru', |
| 'hanime1', |
| 'iwara', |
| 'javbus', |
| 'javdb', |
| 'javlibrary', |
| 'javtiful', |
| 'javtrailers', |
| 'jpxgmn', |
| 'kemono', |
| 'kisskiss', |
| 'komiic', |
| 'konachan', |
| 'koyso', |
| 'laimanhua', |
| 'literotica', |
| 'mangadex', |
| 'manhuagui', |
| 'manyvids', |
| 'missav', |
| 'netflav', |
| 'nhentai', |
| 'olevod', |
| 'oreno3d', |
| 'patreon', |
| 'pixiv', |
| 'pornhub', |
| 'rawkuma', |
| 'sehuatang', |
| 'shuiguopai', |
| 'sis001', |
| 'skeb', |
| 'skebetter', |
| 'spankbang', |
| 't66y', |
| 'uraaka-joshi', |
| 'wnacg', |
| 'xbookcn', |
| 'xmanhua', |
| 'xsijishe', |
| 'yande', |
| 'zaimanhua', |
| 'zodgame', |
| '4kup', |
| 'misskon', |
| '4khd', |
| ]; |
|
|
| |
| function isNsfwRoute(filePath) { |
| const normalizedPath = filePath.replaceAll('\\', '/'); |
| return nsfwRoutes.some((nsfwKey) => { |
| const routePattern = `/lib/routes/${nsfwKey}/`; |
| return normalizedPath.includes(routePattern); |
| }); |
| } |
|
|
| export default { |
| meta: { |
| name: '@rsshub/nsfw-flag', |
| version: '1.0.0', |
| }, |
| configs: { |
| recommended: { |
| plugins: { |
| '@rsshub/nsfw-flag': 'self', |
| }, |
| rules: { |
| '@rsshub/nsfw-flag/add-nsfw-flag': 'error', |
| }, |
| }, |
| }, |
| rules: { |
| 'add-nsfw-flag': { |
| meta: { |
| type: 'problem', |
| docs: { |
| description: 'Automatically add nsfw flag to NSFW routes', |
| category: 'Best Practices', |
| recommended: true, |
| }, |
| fixable: 'code', |
| schema: [], |
| messages: { |
| missingNsfwFlag: 'NSFW route is missing the nsfw flag in features', |
| }, |
| }, |
| create(context) { |
| const filename = context.filename || context.getFilename(); |
|
|
| |
| if (!isNsfwRoute(filename)) { |
| return {}; |
| } |
|
|
| return { |
| ExportNamedDeclaration(node) { |
| |
| if ( |
| node.declaration && |
| node.declaration.type === 'VariableDeclaration' && |
| node.declaration.declarations && |
| node.declaration.declarations[0] && |
| node.declaration.declarations[0].id && |
| node.declaration.declarations[0].id.name === 'route' |
| ) { |
| const routeDeclaration = node.declaration.declarations[0]; |
| const routeObject = routeDeclaration.init; |
|
|
| if (routeObject && routeObject.type === 'ObjectExpression') { |
| let featuresProperty = null; |
| let nsfwProperty = null; |
|
|
| |
| for (const prop of routeObject.properties) { |
| if (prop.type === 'Property' && prop.key && prop.key.name === 'features') { |
| featuresProperty = prop; |
|
|
| |
| if (prop.value && prop.value.type === 'ObjectExpression') { |
| for (const featureProp of prop.value.properties) { |
| if (featureProp.type === 'Property' && featureProp.key && featureProp.key.name === 'nsfw') { |
| nsfwProperty = featureProp; |
| break; |
| } |
| } |
| } |
| break; |
| } |
| } |
|
|
| |
| if (!featuresProperty) { |
| |
| context.report({ |
| node: routeObject, |
| messageId: 'missingNsfwFlag', |
| fix(fixer) { |
| |
| const lastProperty = routeObject.properties.at(-1); |
|
|
| return lastProperty |
| ? fixer.insertTextAfter(lastProperty, ',\n features: {\n nsfw: true,\n }') |
| : |
| fixer.insertTextAfter(routeObject.properties.length > 0 ? routeObject.properties.at(-1) : routeObject, '\n features: {\n nsfw: true,\n }\n'); |
| }, |
| }); |
| } else if (!nsfwProperty) { |
| |
| context.report({ |
| node: featuresProperty.value, |
| messageId: 'missingNsfwFlag', |
| fix(fixer) { |
| const featuresObject = featuresProperty.value; |
| if (featuresObject.properties.length > 0) { |
| const lastFeatureProp = featuresObject.properties.at(-1); |
| return fixer.insertTextAfter(lastFeatureProp, ',\n nsfw: true'); |
| } else { |
| |
| return fixer.replaceTextRange([featuresObject.range[0] + 1, featuresObject.range[1] - 1], '\n nsfw: true,\n '); |
| } |
| }, |
| }); |
| } else if (nsfwProperty.value && (nsfwProperty.value.type !== 'Literal' || nsfwProperty.value.value !== true)) { |
| |
| context.report({ |
| node: nsfwProperty.value, |
| messageId: 'missingNsfwFlag', |
| fix(fixer) { |
| return fixer.replaceText(nsfwProperty.value, 'true'); |
| }, |
| }); |
| } |
| } |
| } |
| }, |
| }; |
| }, |
| }, |
| }, |
| }; |
|
|