Skip to content

Commit

Permalink
feat(link-preview): add batch request support
Browse files Browse the repository at this point in the history
  • Loading branch information
datlechin committed Nov 10, 2024
1 parent c2f9598 commit 5cd86ed
Show file tree
Hide file tree
Showing 16 changed files with 566 additions and 176 deletions.
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"license": "MIT",
"require": {
"php": "^8.1",
"flarum/core": "^v1.8",
"spekulatius/phpscraper": "^2.0.0"
"flarum/core": "^1.8",
"spekulatius/phpscraper": "^3.0"
},
"authors": [
{
Expand Down Expand Up @@ -52,12 +52,15 @@
"gitConf": true,
"githubActions": true,
"prettier": true,
"typescript": false,
"typescript": true,
"bundlewatch": false,
"backendTesting": false,
"editorConfig": true,
"styleci": true
}
}
},
"require-dev": {
"laravel/pint": "^1.18"
}
}
10 changes: 7 additions & 3 deletions extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

namespace Datlechin\LinkPreview;

use Datlechin\LinkPreview\Api\Controllers\ScrapperController;
use Datlechin\LinkPreview\Api\Controllers\BatchLinkPreviewController;
use Datlechin\LinkPreview\Api\Controllers\SingleLinkPreviewController;
use Flarum\Extend;

return [
Expand All @@ -25,16 +26,19 @@
new Extend\Locales(__DIR__ . '/locale'),

(new Extend\Routes('api'))
->get('/datlechin-link-preview', 'datlechin-link-preview', ScrapperController::class),
->get('/datlechin-link-preview', 'datlechin-link-preview', SingleLinkPreviewController::class)
->post('/datlechin-link-preview/batch', 'datlechin-link-preview.batch', BatchLinkPreviewController::class),

(new Extend\Settings())
->default('datlechin-link-preview.enable_batch_requests', true)
->default('datlechin-link-preview.blacklist', '')
->default('datlechin-link-preview.whitelist', '')
->default('datlechin-link-preview.use_google_favicons', false)
->default('datlechin-link-preview.convert_media_urls', false)
->default('datlechin-link-preview.cache_time', 60)
->default('datlechin-link-preview.open_links_in_new_tab', true)
->serializeToForum('datlechin-link-preview.blacklist', 'datlechin-link-preview.blacklist')
->serializeToForum('datlechin-link-preview.enableBatchRequests', 'datlechin-link-preview.enable_batch_requests', 'boolval')
->serializeToForum('datlechin-link-preview.blacklist', key: 'datlechin-link-preview.blacklist')
->serializeToForum('datlechin-link-preview.whitelist', 'datlechin-link-preview.whitelist')
->serializeToForum('datlechin-link-preview.useGoogleFavicons', 'datlechin-link-preview.use_google_favicons', 'boolval')
->serializeToForum('datlechin-link-preview.convertMediaURLs', 'datlechin-link-preview.convert_media_urls', 'boolval')
Expand Down
File renamed without changes.
File renamed without changes.
53 changes: 53 additions & 0 deletions js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"prettier": "@flarum/prettier-config",
"devDependencies": {
"@flarum/prettier-config": "^1.0.0",
"flarum-tsconfig": "^1.0.3",
"flarum-webpack-config": "^2.0.2",
"prettier": "^3.3.3",
"typescript": "^4.9.5",
"webpack": "5.96.1",
"webpack-cli": "^5.1.4"
},
Expand Down
6 changes: 6 additions & 0 deletions js/src/admin/index.js → js/src/admin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ const PREFIX = 'datlechin-link-preview';
app.initializers.add('datlechin/flarum-link-preview', () => {
app.extensionData
.for(PREFIX)
.registerSetting({
setting: `${PREFIX}.enable_batch_requests`,
label: app.translator.trans(`${PREFIX}.admin.settings.enable_batch_requests_label`),
help: app.translator.trans(`${PREFIX}.admin.settings.enable_batch_requests_help`),
type: 'checkbox',
})
.registerSetting({
setting: `${PREFIX}.convert_media_urls`,
label: app.translator.trans(`${PREFIX}.admin.settings.convert_media_urls_label`),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import Component from 'flarum/common/Component';
import icon from 'flarum/common/helpers/icon';
import Link from 'flarum/common/components/Link';
import classList from 'flarum/common/utils/classList';
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
import batchManager from '../utils/batch-manager';
import type Mithril from 'mithril';

export default class LinkPreview extends Component {
oninit(vnode) {
interface LinkPreviewAttrs {
link: HTMLAnchorElement;
openLinksInNewTab: boolean;
useGoogleFavicons: boolean;
}

interface LinkPreviewData {
title?: string;
description?: string;
site_name?: string;
image?: string;
error?: string;
}

export default class LinkPreview extends Component<LinkPreviewAttrs> {
loading!: boolean;
link!: HTMLAnchorElement;
linkAttributes!: { [key: string]: string };
linkClasses!: string;
data!: LinkPreviewData | null;
useGoogleFavicons!: boolean;

oninit(vnode: Mithril.Vnode<LinkPreviewAttrs, this>) {
super.oninit(vnode);

const attrs = vnode.attrs;
Expand Down Expand Up @@ -41,7 +63,7 @@ export default class LinkPreview extends Component {
) : null}
<div className="LinkPreview-main">
<div className="LinkPreview-title">{this.getLink(this.data?.title ?? this.data?.error)}</div>
<div className="LinkPreview-description">{this.loading ? '' : this.data?.description ?? ''}</div>
<div className="LinkPreview-description">{this.loading ? '' : (this.data?.description ?? '')}</div>
<div className="LinkPreview-domain">
{this.useGoogleFavicons ? <img src={this.getFavicon()} data-link-preview /> : icon('fas fa-external-link-alt')}
{this.getLink(this.data?.site_name)}
Expand All @@ -51,14 +73,16 @@ export default class LinkPreview extends Component {
);
}

oncreate(vnode) {
this.link.parentNode.insertBefore(vnode.dom, this.link);
oncreate(vnode: Mithril.VnodeDOM<LinkPreviewAttrs, this>) {
if (this.link.parentNode) {
this.link.parentNode.insertBefore(vnode.dom, this.link);
}
}

getLink(text) {
getLink(text?: string) {
return (
<a {...this.linkAttributes} className={classList('LinkPreview-link', this.linkClasses)}>
{this.loading ? this.getDomain() : text ?? this.getDomain()}
{this.loading ? this.getDomain() : (text ?? this.getDomain())}
</a>
);
}
Expand All @@ -80,18 +104,14 @@ export default class LinkPreview extends Component {
}

fetchData() {
app
.request({
url: `${app.forum.attribute('apiUrl')}/datlechin-link-preview?url=${encodeURIComponent(this.getHref())}`,
method: 'GET',
})
.then((data) => {
this.setData(data);
this.loading = false;
});
batchManager.add(this.getHref(), (data: LinkPreviewData) => {
this.setData(data);
this.loading = false;
m.redraw();
});
}

setData(data) {
setData(data: LinkPreviewData) {
this.data = data;
m.redraw();
}
Expand Down
18 changes: 9 additions & 9 deletions js/src/forum/index.js → js/src/forum/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import LinkPreview from './components/LinkPreview';

app.initializers.add('datlechin/flarum-link-preview', () => {
extend(CommentPost.prototype, 'refreshContent', function () {
const getMultiDimensionalSetting = (key) => {
const setting = app.forum.attribute(key);
const getMultiDimensionalSetting = (key: string): string[] => {
const setting = app.forum.attribute<string>(key);
return setting ? setting.split(/[,\n]/).map((item) => item.trim()) : [];
};

const inList = (needle, haystack) => {
if (0 === haystack.length) {
const inList = (needle: string, haystack: string[]): boolean => {
if (haystack.length === 0) {
return false;
}
if (haystack.includes(needle)) {
Expand All @@ -31,18 +31,18 @@ app.initializers.add('datlechin/flarum-link-preview', () => {

const blacklistArray = getMultiDimensionalSetting('datlechin-link-preview.blacklist');
const whitelistArray = getMultiDimensionalSetting('datlechin-link-preview.whitelist');
const convertMediaUrls = app.forum.attribute('datlechin-link-preview.convertMediaURLs') ?? false;
const useGoogleFavicons = app.forum.attribute('datlechin-link-preview.useGoogleFavicons') ?? false;
const openLinksInNewTab = app.forum.attribute('datlechin-link-preview.openLinksInNewTab') ?? false;
const convertMediaUrls = app.forum.attribute<boolean>('datlechin-link-preview.convertMediaURLs') ?? false;
const useGoogleFavicons = app.forum.attribute<boolean>('datlechin-link-preview.useGoogleFavicons') ?? false;
const openLinksInNewTab = app.forum.attribute<boolean>('datlechin-link-preview.openLinksInNewTab') ?? false;
const linkSelectorExcludes = ['.PostMention', '.UserMention', '.LinkPreview-link', '.LinkPreview-captured'].map((cls) => `:not(${cls})`).join('');

this.element.querySelectorAll(`.Post-body a[rel]${linkSelectorExcludes}`).forEach((link) => {
this.element.querySelectorAll<HTMLAnchorElement>(`.Post-body a[rel]${linkSelectorExcludes}`).forEach((link) => {
const normalizedUrl = link.href.replace(/^https?:\/\/(.+?)\/?$/i, '$1');

if (
(whitelistArray.length && !inList(normalizedUrl, whitelistArray)) ||
(blacklistArray.length && inList(normalizedUrl, blacklistArray)) ||
link.href.replace(/\/$/, '') !== link.textContent.replace(/\/$/, '')
link.href.replace(/\/$/, '') !== (link.textContent?.replace(/\/$/, '') ?? '')
) {
return;
}
Expand Down
Loading

0 comments on commit 5cd86ed

Please sign in to comment.