4chan-full
Advanced tools
Comparing version 1.0.7 to 1.0.8
@@ -6,15 +6,15 @@ let { JSDOM } = require("jsdom"); | ||
function parseBody(siteBodyHTML="") { | ||
function parseBody(siteBodyHTML = "") { | ||
let dom = new JSDOM(siteBodyHTML); | ||
let document = dom.window.document; | ||
let doc = dom.window.document; | ||
let trs = Array.from(document.querySelectorAll("#arc-list tr")); | ||
let trs = Array.from(doc.querySelectorAll("#arc-list tr")); | ||
trs.shift(); | ||
let board = boardTitleToBoardNameInfo(document.querySelector(".boardTitle").textContent); | ||
let board = boardTitleToBoardNameInfo(doc.querySelector(".boardTitle").textContent); | ||
let result = { | ||
board, | ||
threads: trs.map(e=>{ | ||
threads: trs.map(e => { | ||
let id = parseInt(e.cells[0].textContent); | ||
@@ -24,3 +24,3 @@ return { | ||
teaser: e.cells[1].textContent, | ||
thread(dataPipe="") { | ||
thread(dataPipe = "") { | ||
return getThread(board.name, id, dataPipe); | ||
@@ -38,9 +38,13 @@ } | ||
async function getBody(board="", dataPipe="") { | ||
async function getBody(board = "", dataPipe = "") { | ||
let archiveURL = `https://boards.4channel.org/${board}/archive`; | ||
let bodyHTML = await got.get(dataPipe+archiveURL, {resolveBodyOnly: true}); | ||
let bodyHTML = await got.get(dataPipe + archiveURL, { resolveBodyOnly: true }); | ||
return bodyHTML; | ||
} | ||
async function getArchive(board="", dataPipe="") { | ||
/** | ||
* @param {String} board Board code | ||
* @param {String} dataPipe DataPipe url | ||
*/ | ||
async function getArchive(board = "", dataPipe = "") { | ||
let bodyHTML = await getBody(board, dataPipe); | ||
@@ -47,0 +51,0 @@ let parsedBody = parseBody(bodyHTML); |
let { JSDOM } = require("jsdom"); | ||
let got = require("got").default; | ||
let { fileTextToSizeInfo, boardTitleToBoardNameInfo } = require("./utils"); | ||
let { fileTextToSizeInfo, boardTitleToBoardNameInfo, fileElementToFileObject, parsePostMessage } = require("./utils"); | ||
let getThread = require("./getThread"); | ||
let getArchive = require("./getArchive"); | ||
function parseBody(siteBodyHTML="") { | ||
function parseBody(siteBodyHTML = "") { | ||
let dom = new JSDOM(siteBodyHTML); | ||
let document = dom.window.document; | ||
let doc = dom.window.document; | ||
let board = boardTitleToBoardNameInfo(document.querySelector(".boardTitle").textContent); | ||
let board = boardTitleToBoardNameInfo(doc.querySelector(".boardTitle").textContent); | ||
let result = { | ||
let result = { | ||
board, | ||
threads: Array.from(document.querySelectorAll(".thread")).map(e=>{ | ||
let id = parseInt(e.id.replace(/[^0-9]/g,"")); | ||
threads: Array.from(doc.querySelectorAll(".thread")).map(e => { | ||
let id = parseInt(e.id.replace(/[^0-9]/g, "")); | ||
return { | ||
id, | ||
thread(dataPipe="") { | ||
thread(dataPipe = "") { | ||
return getThread(board.name, id, dataPipe); | ||
}, | ||
subject: e.querySelector(".op .desktop .subject").textContent, | ||
message: e.querySelector(".postMessage") ? e.querySelector(".postMessage").textContent.replace(/(>>\d+)/gm, " [$1] ") : "", | ||
message: e.querySelector(".postMessage") ? parsePostMessage(e.querySelector(".postMessage").textContent) : "", | ||
date: parseInt(e.querySelector(".dateTime").getAttribute("data-utc")), | ||
file: e.querySelector(".file") ? { | ||
exists: true, | ||
url: "https:"+e.querySelector(".fileText a").getAttribute("href"), | ||
name: e.querySelector(".fileText a").title ? e.querySelector(".fileText a").title : e.querySelector(".fileText a").textContent, | ||
size: fileTextToSizeInfo(e.querySelector(".fileText").textContent) | ||
} : {exists: false} | ||
file: fileElementToFileObject(e.querySelector(".file")) | ||
} | ||
}), | ||
page: parseInt(document.querySelector(".pages strong").textContent), | ||
hasNextPage: Boolean(document.querySelector(".next .pageSwitcherForm")) | ||
page: parseInt(doc.querySelector(".pages strong").textContent), | ||
hasNextPage: Boolean(doc.querySelector(".next .pageSwitcherForm")), | ||
archive(dataPipe = "") { | ||
return getArchive(board.code, dataPipe); | ||
} | ||
} | ||
@@ -42,5 +41,5 @@ | ||
async function getBody(board="", page=1, dataPipe="") { | ||
async function getBody(board = "", page = 1, dataPipe = "") { | ||
let threadURL = `https://boards.4channel.org/${board}/${page <= 1 ? "" : page}`; | ||
let bodyHTML = await got.get(dataPipe+threadURL, {resolveBodyOnly: true}); | ||
let bodyHTML = await got.get(dataPipe + threadURL, { resolveBodyOnly: true }); | ||
return bodyHTML; | ||
@@ -50,8 +49,7 @@ } | ||
/** | ||
* | ||
* @param {String} board | ||
* @param {Number} page | ||
* @param {String} dataPipe | ||
* @param {String} board Board code | ||
* @param {Number} page Page number | ||
* @param {String} dataPipe DataPipe url | ||
*/ | ||
async function getBoard(board="", page=1, dataPipe="") { | ||
async function getBoard(board = "", page = 1, dataPipe = "") { | ||
let bodyHTML = await getBody(board, page, dataPipe); | ||
@@ -58,0 +56,0 @@ let bodyJSON = parseBody(bodyHTML); |
@@ -1,4 +0,4 @@ | ||
let {JSDOM} = require("jsdom"); | ||
let { JSDOM } = require("jsdom"); | ||
let got = require("got").default; | ||
let {convertSafetyType} = require("./utils"); | ||
let { convertSafetyType } = require("./utils"); | ||
let getThread = require("./getThread"); | ||
@@ -13,5 +13,5 @@ | ||
let dom = new JSDOM(siteBodyHTML); | ||
let document = dom.window.document; | ||
let doc = dom.window.document; | ||
let result = Array.from(document.querySelectorAll(".c-thread")).map(e => { | ||
let result = Array.from(doc.querySelectorAll(".c-thread")).map(e => { | ||
let id = parseInt(e.querySelector("a").getAttribute("href").split("/")[5]); | ||
@@ -25,3 +25,3 @@ let boardName = e.querySelector(".c-board").textContent; | ||
id, | ||
thread(dataPipe="") { | ||
thread(dataPipe = "") { | ||
return getThread(boardName, id, dataPipe); | ||
@@ -55,3 +55,4 @@ }, | ||
/** | ||
* @param {SafetyType} type | ||
* @param {SafetyType} type Safety Type | ||
* @param {String} dataPipe DataPipe URL | ||
*/ | ||
@@ -58,0 +59,0 @@ async function getPopularThreads(type = "WORKSAFE", dataPipe = "") { |
@@ -5,11 +5,11 @@ let { JSDOM } = require("jsdom"); | ||
function parseBody(siteBodyHTML="") { | ||
function parseBody(siteBodyHTML = "") { | ||
let dom = new JSDOM(siteBodyHTML); | ||
let document = dom.window.document; | ||
let doc = dom.window.document; | ||
let statsArray = Array.from(document.querySelectorAll("#site-stats .stat-cell")).map(i=>i.childNodes[1].textContent.trim()); | ||
let statsArray = Array.from(doc.querySelectorAll("#site-stats .stat-cell")).map(i => i.childNodes[1].textContent.trim()); | ||
let result = { | ||
totalPosts: parseInt(statsArray[0].replace(/\,/g,"")), | ||
currentUsers: parseInt(statsArray[1].replace(/\,/g,"")), | ||
totalPosts: parseInt(statsArray[0].replace(/\,/g, "")), | ||
currentUsers: parseInt(statsArray[1].replace(/\,/g, "")), | ||
activeContent: reverseFormatFileSizeKB(statsArray[2]) | ||
@@ -25,8 +25,11 @@ }; | ||
async function getBody(dataPipe="") { | ||
let bodyHTML = await got.get(dataPipe+"https://www.4chan.org/", {resolveBodyOnly: true}); | ||
async function getBody(dataPipe = "") { | ||
let bodyHTML = await got.get(dataPipe + "https://www.4chan.org/", { resolveBodyOnly: true }); | ||
return bodyHTML; | ||
} | ||
async function getStats(dataPipe="") { | ||
/** | ||
* @param {String} dataPipe DataPipe URL | ||
*/ | ||
async function getStats(dataPipe = "") { | ||
let bodyHTML = await getBody(dataPipe); | ||
@@ -33,0 +36,0 @@ let parsedBody = parseBody(bodyHTML); |
let { JSDOM } = require("jsdom"); | ||
let got = require("got").default; | ||
let { fileTextToSizeInfo, boardTitleToBoardNameInfo } = require("./utils"); | ||
let { fileTextToSizeInfo, boardTitleToBoardNameInfo, fileElementToFileObject, parsePostMessage } = require("./utils"); | ||
function parseBody(siteBodyHTML="") { | ||
function parseBody(siteBodyHTML = "") { | ||
let dom = new JSDOM(siteBodyHTML); | ||
let document = dom.window.document; | ||
let doc = dom.window.document; | ||
let result = { | ||
subject: document.querySelector(".subject").textContent, | ||
board: boardTitleToBoardNameInfo(document.querySelector(".boardTitle").textContent), | ||
posts: Array.from(document.querySelectorAll(".postContainer")).map(e => { | ||
subject: doc.querySelector(".subject").textContent, | ||
board: boardTitleToBoardNameInfo(doc.querySelector(".boardTitle").textContent), | ||
posts: Array.from(doc.querySelectorAll(".postContainer")).map(e => { | ||
let fileSizeInfo = []; | ||
@@ -17,13 +17,8 @@ if (e.querySelector(".file")) fileSizeInfo = fileTextToSizeInfo(e.querySelector(".fileText").textContent); | ||
id: parseInt(e.id.replace(/[^0-9]/g, "")), | ||
message: e.querySelector(".postMessage") ? e.querySelector(".postMessage").textContent.replace(/(>>\d+)/gm, " [$1] ") : "", | ||
file: e.querySelector(".file") ? { | ||
name: e.querySelector(".fileText a").getAttribute("title") ? e.querySelector(".fileText a").getAttribute("title") : e.querySelector(".fileText a").textContent, | ||
url: "https:" + e.querySelector(".fileText a").getAttribute("href"), | ||
exists: true, | ||
size: fileTextToSizeInfo(e.querySelector(".fileText").textContent) | ||
} : { exists: false }, | ||
message: e.querySelector(".postMessage") ? parsePostMessage(e.querySelector(".postMessage").textContent) : "", | ||
file: fileElementToFileObject(e.querySelector(".file")), | ||
date: parseInt(e.querySelector(".dateTime").getAttribute("data-utc")) | ||
} | ||
}), | ||
isArchived: Boolean(document.querySelector(".closed")) | ||
isArchived: Boolean(doc.querySelector(".closed")) | ||
}; | ||
@@ -36,9 +31,14 @@ | ||
async function getBody(board="", threadId=0, dataPipe="") { | ||
async function getBody(board = "", threadId = 0, dataPipe = "") { | ||
let threadURL = `https://boards.4channel.org/${board}/thread/${threadId}`; | ||
let bodyHTML = await got.get(dataPipe+threadURL, {resolveBodyOnly: true}); | ||
let bodyHTML = await got.get(dataPipe + threadURL, { resolveBodyOnly: true }); | ||
return bodyHTML; | ||
} | ||
async function getThread(board="", threadId=0, dataPipe="") { | ||
/** | ||
* @param {String} board Board code | ||
* @param {Number} threadId Thread id | ||
* @param {String} dataPipe DataPipe URL | ||
*/ | ||
async function getThread(board = "", threadId = 0, dataPipe = "") { | ||
let bodyHTML = await getBody(board, threadId, dataPipe); | ||
@@ -45,0 +45,0 @@ let bodyJSON = parseBody(bodyHTML); |
@@ -6,2 +6,3 @@ let getBoard = require("./getBoard"); | ||
let boards = require("./_boards.min"); | ||
let utils = require("./utils"); | ||
@@ -13,5 +14,6 @@ let FCHF = { | ||
getArchive, | ||
boards | ||
boards, | ||
utils | ||
} | ||
module.exports = FCHF; |
{ | ||
"name": "4chan-full", | ||
"version": "1.0.7", | ||
"description": "www.4chan.org non-official read only api", | ||
"main": "index.js", | ||
"_from": "4chan-full", | ||
"_id": "4chan-full@1.0.72", | ||
"_inBundle": false, | ||
"_integrity": "sha512-pwIjr/EC5gI28qjaxXyMHqI/qVoQuJc2wp8vM9lRrdtAG1waEJTRkclz0U9Cg374tOq/1F1oEUDCCnpazM51sw==", | ||
"_location": "/4chan-full", | ||
"_phantomChildren": {}, | ||
"_requested": { | ||
"type": "tag", | ||
"registry": true, | ||
"raw": "4chan-full", | ||
"name": "4chan-full", | ||
"escapedName": "4chan-full", | ||
"rawSpec": "", | ||
"saveSpec": null, | ||
"fetchSpec": "latest" | ||
}, | ||
"_requiredBy": [ | ||
"#USER", | ||
"/" | ||
], | ||
"_resolved": "https://registry.npmjs.org/4chan-full/-/4chan-full-1.0.72.tgz", | ||
"_shasum": "0e3267f40a1af1fb47595a5e1556bccf47abfc6f", | ||
"_spec": "4chan-full", | ||
"_where": "D:\\BDT\\Desktop\\Projelerim\\JavaScript\\4chan-full", | ||
"author": { | ||
"name": "Kıraç Armağan Önal" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Armagann/4chan-full/issues" | ||
}, | ||
"bundleDependencies": false, | ||
"dependencies": { | ||
@@ -10,6 +37,6 @@ "got": "^11.4.0", | ||
}, | ||
"deprecated": false, | ||
"description": "www.4chan.org non-official read only api", | ||
"devDependencies": {}, | ||
"scripts": { | ||
"test": "node test.js" | ||
}, | ||
"homepage": "https://github.com/Armagann/4chan-full#readme", | ||
"keywords": [ | ||
@@ -23,4 +50,5 @@ "4chan", | ||
], | ||
"author": "Kıraç Armağan Önal", | ||
"license": "Apache-2.0", | ||
"main": "index.js", | ||
"name": "4chan-full", | ||
"repository": { | ||
@@ -30,6 +58,6 @@ "type": "git", | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Armagann/4chan-full/issues" | ||
"scripts": { | ||
"test": "node test.js" | ||
}, | ||
"homepage": "https://github.com/Armagann/4chan-full#readme" | ||
"version": "1.0.8" | ||
} |
> # 4CHAN-FULL 🎉 | ||
> | ||
> www.4chan.org non-official read only api. | ||
@@ -7,2 +8,3 @@ | ||
## Installation | ||
```diff | ||
@@ -15,2 +17,3 @@ npm install 4chan-full | ||
### Possibilities | ||
- [Get Thread](https://example.com/ "Example Result") (`.getThread(boardCode, threadId)`) | ||
@@ -26,2 +29,3 @@ - [Get Board](https://example.com/ "Example Result") (`.getBoard(boardCode, page)`) | ||
### Example `Basic Thread Files Downloader Example` | ||
```js | ||
@@ -36,39 +40,65 @@ // To be honest there is no good examples to use. :D | ||
// | | | | ||
FCHF.getThread("w","2148861", "https://kao-datapipe-2.herokuapp.com/").then(thread=>{ | ||
console.log("subject", thread.subject) | ||
console.log("isArchived", thread.isArchived) | ||
thread.posts.forEach((post, index)=>{ | ||
console.log(index, "", post.message) | ||
if (post.file.exists) { | ||
// Size in KB | ||
console.log(post.file.url, post.file.name, post.file.size.size, post.file.size.width, post.file.size.height); | ||
setTimeout(()=>{ | ||
download("https://kao-datapipe-1.herokuapp.com/"+post.file.url, "wallpapers", { | ||
filename: post.file.name | ||
}) | ||
}, (index*(Math.random()*1000))+1) | ||
} | ||
FCHF.getThread("w", "2148861", "https://kao-datapipe-2.herokuapp.com/").then( | ||
(thread) => { | ||
console.log("subject", thread.subject); | ||
console.log("isArchived", thread.isArchived); | ||
thread.posts.forEach((post, index) => { | ||
console.log(index, "", post.message); | ||
if (post.file.exists) { | ||
console.log( | ||
post.file.url, | ||
post.file.name, | ||
// Size in KB | ||
post.file.size.size, | ||
post.file.size.width, | ||
post.file.size.height | ||
); | ||
setTimeout(() => { | ||
download( | ||
"https://kao-datapipe-1.herokuapp.com/" + post.file.url, | ||
"wallpapers", | ||
{ | ||
filename: post.file.name, | ||
} | ||
); | ||
}, index * (Math.random() * 1000) + 1); | ||
} | ||
}); | ||
}); | ||
} | ||
); | ||
``` | ||
--- | ||
--- | ||
### Update 1.0.6 | ||
### Update 1.0.8 | ||
You can get thread directly from getBoard response or getPopularThreads response. **Example:** | ||
- Thread's `message` property is changed is no longer a string its a Object that object contains full raw message and quotes of the message if exists. The new message format: | ||
```js | ||
FCHF.getBoard().then(async board=>{ | ||
let firstThread = await board.threads[0].thread(); | ||
console.log(firstThread); | ||
}) | ||
{ | ||
content: "hey bro! >>46831", | ||
quotes: [ | ||
{ | ||
id: "46831", | ||
index: 9 | ||
} | ||
] | ||
} | ||
``` | ||
### Update 1.0.7 | ||
- In file object changed property `exists` to `isExists` | ||
- Added file object to `isSpoiler` property | ||
- Now you can get board's archive directly form getBoard | ||
### Update 1.0.6 | ||
You can get thread directly from getBoard response or getPopularThreads response. **Example:** | ||
```js | ||
FCHF.getBoard().then(async (board) => { | ||
let firstThread = await board.threads[0].thread(); | ||
console.log(firstThread); | ||
}); | ||
``` |
10
test.js
let FCHF = require("./index"); | ||
FCHF.getBoard("w",1,"https://kao-datapipe-2.herokuapp.com/").then(async data=>{ | ||
let thread = await data.threads[0].thread("https://kao-datapipe-1.herokuapp.com/"); | ||
console.log(thread.posts); | ||
// FCHF.getBoard("jp",1,"https://kao-datapipe-2.herokuapp.com/").then(async data=>{ | ||
// let thread = await data.threads[0].thread("https://kao-datapipe-1.herokuapp.com/"); | ||
// console.log(thread) | ||
// }) | ||
FCHF.getThread("jp",26175111,"https://kao-datapipe-2.herokuapp.com/").then(thread=>{ | ||
console.log(thread.posts.map(f=>f.file)) | ||
}) |
55
utils.js
let safetyKeyValues = [{ | ||
keys: ["ws", "WORKSAFE", 0], | ||
value: "ws" | ||
}, | ||
{ | ||
keys: ["nws", "nsfw", "NOTSAFE", "NOTWORKSAFE", 1], | ||
value: "nws" | ||
}, | ||
{ | ||
keys: ["all", "ALL", "COMBINED", 2], | ||
value: "all" | ||
} | ||
keys: ["ws", "WORKSAFE", 0], | ||
value: "ws" | ||
}, | ||
{ | ||
keys: ["nws", "nsfw", "NOTSAFE", "NOTWORKSAFE", 1], | ||
value: "nws" | ||
}, | ||
{ | ||
keys: ["all", "ALL", "COMBINED", 2], | ||
value: "all" | ||
} | ||
]; | ||
@@ -25,6 +25,7 @@ | ||
let based = safetyKeyValues.find(i => i.keys.some(i => i == type)); | ||
if (!based) throw new Error(`Invalid safety type. (Only possible: ${safetyKeyValues.map(i=>i.keys).join(", ")})`); | ||
if (!based) throw new Error(`Invalid safety type. (Only possible: ${safetyKeyValues.map(i => i.keys).join(", ")})`); | ||
return based.value; | ||
} | ||
/** @returns {{code: string, name: string}} */ | ||
function boardTitleToBoardNameInfo(boardTitle = "") { | ||
@@ -38,3 +39,4 @@ let boardTitleSplitted = boardTitle.split("-").map(i => i.trim()); | ||
function reverseFormatFileSizeKB(fileSizeText="0 GB") { | ||
/** @returns {number} */ | ||
function reverseFormatFileSizeKB(fileSizeText = "0 GB") { | ||
let splitted = fileSizeText.split(" "); | ||
@@ -60,2 +62,3 @@ let factor = NaN; | ||
/** @returns {{size: string, width: number, height: number}} */ | ||
function fileTextToSizeInfo(ft = "") { | ||
@@ -72,2 +75,24 @@ let info = ft.slice(ft.lastIndexOf("(") + 1, ft.lastIndexOf(")")).split(", "); | ||
/** @returns {{name?:string,url?:string,isExists:boolean,size:{size: string, width: number, height: number}, isSpoiler: boolean}} */ | ||
function fileElementToFileObject(e) { | ||
if (!e) return { isExists: false }; | ||
let isSpoiler = Boolean(e.querySelector(".imgspoiler")); | ||
return { | ||
name: isSpoiler ? e.querySelector(".fileText").getAttribute("title") : (e.querySelector(".fileText a").getAttribute("title") ? e.querySelector(".fileText a").getAttribute("title") : e.querySelector(".fileText a").textContent), | ||
url: "https:" + e.querySelector(".fileText a").getAttribute("href"), | ||
isExists: true, | ||
size: fileTextToSizeInfo(e.querySelector(".fileText").textContent), | ||
isSpoiler | ||
} | ||
} | ||
/** @returns {{content: string, quotes: Array<{id: string, index: number}>}} */ | ||
function parsePostMessage(t = "") { | ||
let matches = Array.from(t.matchAll(/>>(\d+)/gmi)); | ||
return { | ||
content: t, | ||
quotes: matches.map(i => ({ id: i[0], index: i.index })) | ||
} | ||
} | ||
let utils = { | ||
@@ -77,5 +102,7 @@ fileTextToSizeInfo, | ||
convertSafetyType, | ||
reverseFormatFileSizeKB | ||
reverseFormatFileSizeKB, | ||
fileElementToFileObject, | ||
parsePostMessage | ||
} | ||
module.exports = utils; |
19826
331
101