176 lines
4.5 KiB
TypeScript
176 lines
4.5 KiB
TypeScript
// Copyright (c) 2021 MillenniumEarl
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
"use strict";
|
|
|
|
// Public modules from npm
|
|
import cheerio from "cheerio";
|
|
|
|
// Modules from file
|
|
import PlatformUser from "./platform-user";
|
|
import { IPostElement, parseF95ThreadPost } from "../../scrape-data/post-parse";
|
|
import { POST, THREAD } from "../../constants/css-selector";
|
|
import { urls } from "../../constants/url";
|
|
import { fetchHTML } from "../../network-helper";
|
|
import shared from "../../shared";
|
|
import { InvalidID, INVALID_POST_ID, UserNotLogged, USER_NOT_LOGGED } from "../errors";
|
|
import { ILazy } from "../../interfaces";
|
|
|
|
/**
|
|
* Represents a post published by a user on the F95Zone platform.
|
|
*/
|
|
export default class Post implements ILazy {
|
|
//#region Fields
|
|
|
|
private _id: number;
|
|
private _number: number;
|
|
private _published: Date;
|
|
private _lastEdit: Date;
|
|
private _owner: PlatformUser;
|
|
private _bookmarked: boolean;
|
|
private _message: string;
|
|
private _body: IPostElement[];
|
|
|
|
//#endregion Fields
|
|
|
|
//#region Getters
|
|
|
|
/**
|
|
* Represents a post published by a user on the F95Zone platform.
|
|
*/
|
|
public get id(): number {
|
|
return this._id;
|
|
}
|
|
/**
|
|
* Unique ID of the post within the thread in which it is present.
|
|
*/
|
|
public get number(): number {
|
|
return this._number;
|
|
}
|
|
/**
|
|
* Date the post was first published.
|
|
*/
|
|
public get published(): Date {
|
|
return this._published;
|
|
}
|
|
/**
|
|
* Date the post was last modified.
|
|
*/
|
|
public get lastEdit(): Date {
|
|
return this._lastEdit;
|
|
}
|
|
/**
|
|
* User who owns the post.
|
|
*/
|
|
public get owner(): PlatformUser {
|
|
return this._owner;
|
|
}
|
|
/**
|
|
* Indicates whether the post has been bookmarked.
|
|
*/
|
|
public get bookmarked(): boolean {
|
|
return this._bookmarked;
|
|
}
|
|
/**
|
|
* Post message text.
|
|
*/
|
|
public get message(): string {
|
|
return this._message;
|
|
}
|
|
/**
|
|
* Set of the elements that make up the body of the post.
|
|
*/
|
|
public get body(): IPostElement[] {
|
|
return this._body;
|
|
}
|
|
|
|
//#endregion Getters
|
|
|
|
constructor(id: number) {
|
|
this._id = id;
|
|
}
|
|
|
|
//#region Public methods
|
|
|
|
/**
|
|
* Gets the post data starting from its unique ID for the entire platform.
|
|
*/
|
|
public async fetch(): Promise<void> {
|
|
// Check login
|
|
if (!shared.isLogged) throw new UserNotLogged(USER_NOT_LOGGED);
|
|
|
|
// Check ID
|
|
if (!this.id || this.id < 1) throw new InvalidID(INVALID_POST_ID);
|
|
|
|
// Fetch HTML page containing the post
|
|
const url = new URL(this.id.toString(), urls.POSTS).toString();
|
|
const response = await fetchHTML(url);
|
|
|
|
if (response.isSuccess()) await this.elaborateResponse(response.value);
|
|
else throw response.value;
|
|
}
|
|
|
|
//#endregion Public methods
|
|
|
|
//#region Private methods
|
|
|
|
/**
|
|
* Process the HTML code received as
|
|
* an answer and gets the data contained in it.
|
|
*/
|
|
private async elaborateResponse(html: string) {
|
|
// Load cheerio and find post
|
|
const $ = cheerio.load(html);
|
|
|
|
const post = $(THREAD.POSTS_IN_PAGE)
|
|
.toArray()
|
|
.find((el, idx) => {
|
|
// Fetch the ID and check if it is what we are searching
|
|
const sid: string = $(el).find(POST.ID).attr("id").replace("post-", "");
|
|
const id = parseInt(sid, 10);
|
|
|
|
if (id === this.id) return el;
|
|
});
|
|
|
|
// Finally parse the post
|
|
await this.parsePost($, $(post));
|
|
}
|
|
|
|
private async parsePost($: cheerio.Root, post: cheerio.Cheerio): Promise<void> {
|
|
// Find post's ID
|
|
const sid: string = post.find(POST.ID).attr("id").replace("post-", "");
|
|
this._id = parseInt(sid, 10);
|
|
|
|
// Find post's number
|
|
const sNumber: string = post.find(POST.NUMBER).text().replace("#", "");
|
|
this._number = parseInt(sNumber, 10);
|
|
|
|
// Find post's publishing date
|
|
const sPublishing: string = post.find(POST.PUBLISH_DATE).attr("datetime");
|
|
this._published = new Date(sPublishing);
|
|
|
|
// Find post's last edit date
|
|
const sLastEdit: string = post.find(POST.LAST_EDIT).attr("datetime");
|
|
this._lastEdit = new Date(sLastEdit);
|
|
|
|
// Find post's owner
|
|
const sOwnerID: string = post.find(POST.OWNER_ID).attr("data-user-id").trim();
|
|
this._owner = new PlatformUser(parseInt(sOwnerID, 10));
|
|
await this._owner.fetch();
|
|
|
|
// Find if the post is bookmarked
|
|
this._bookmarked = post.find(POST.BOOKMARKED).length !== 0;
|
|
|
|
// Find post's message
|
|
this._message = post.find(POST.BODY).text();
|
|
|
|
// Parse post's body
|
|
const body = post.find(POST.BODY);
|
|
this._body = parseF95ThreadPost($, body);
|
|
}
|
|
|
|
//#endregion
|
|
}
|