Skip to content

Commit

Permalink
Merge pull request #6 from Ray-D-Song/plugin
Browse files Browse the repository at this point in the history
Plugin
  • Loading branch information
Ray-D-Song authored Oct 27, 2024
2 parents 2ae29c7 + 519a36f commit d7e5ba0
Show file tree
Hide file tree
Showing 21 changed files with 559 additions and 182 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/preview-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Build and Release

on:
push:
branches:
- plugin
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20

- name: Install pnpm
run: |
npm install -g pnpm
- name: Install dependencies
run: pnpm install

- name: Build plugin
run: pnpm build:plugin

- name: Zip extension folder
run: |
cd dist/extension
zip -r ../../extension.zip .
- name: Upload extension
uses: actions/upload-artifact@v4
with:
name: extension
path: extension.zip
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ name: Deploy-Preview
on:
push:
branches:
- showcase
- dev
- main
- hotfix

jobs:
deploy:
Expand Down
80 changes: 44 additions & 36 deletions packages/plugin/background/background.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Browser from 'webextension-polyfill'
import '~/lib/browser-polyfill.min.js'
import '~/lib/single-file-background.js'
import { onMessage, sendMessage } from 'webext-bridge/background'
import { isNotNil } from '@web-archive/shared/utils'
import { base64ToBlob } from '~/utils/file.js'
import { onMessage } from 'webext-bridge/background'
import { clearFinishedTaskList, createAndRunTask, getTaskList } from './processor'
import { checkLoginStatus, getCacheLoginStatus, resetLoginStatus } from './login'

async function appendAuthHeader(options?: RequestInit) {
const { token } = await Browser.storage.local.get('token') ?? {}
Expand All @@ -22,7 +22,7 @@ async function appendAuthHeader(options?: RequestInit) {
}

/* global RequestInit */
async function request(url: string, options?: RequestInit | undefined) {
export async function request(url: string, options?: RequestInit | undefined) {
const { serverUrl } = await Browser.storage.local.get('serverUrl')
const res = await fetch(`${serverUrl}/api${url}`, {
credentials: 'same-origin',
Expand All @@ -36,6 +36,12 @@ async function request(url: string, options?: RequestInit | undefined) {

throw new Error(json.message)
}

if (res.status === 401) {
await Browser.storage.local.set({ loginStatus: false })
throw new Error('Unauthorized')
}

throw new Error('Failed to fetch')
}

Expand All @@ -52,21 +58,21 @@ onMessage('get-server-url', async () => {
})

onMessage('check-auth', async () => {
try {
await request('/auth', {
method: 'POST',
})
return {
success: true,
}
return {
success: await getCacheLoginStatus(),
}
catch {
return {
success: false,
}
})

onMessage('login', async () => {
return {
success: await checkLoginStatus(),
}
})

onMessage('logout', async () => {
await resetLoginStatus()
})

onMessage('get-token', async () => {
const { token } = await Browser.storage.local.get('token')
return { token }
Expand All @@ -87,32 +93,34 @@ onMessage('get-all-folders', async () => {
})

onMessage('add-save-page-task', async ({ data: { tabId, singleFileSetting, pageForm } }) => {
await Browser.scripting.executeScript({
target: { tabId },
files: ['/lib/single-file.js', '/lib/single-file-extension-core.js'],
createAndRunTask({
tabId,
singleFileSetting,
pageForm,
})
const { content } = await sendMessage('scrape-page-data', singleFileSetting, `content-script@${tabId}`)

const { href, title, pageDesc, folderId, screenshot } = pageForm

const form = new FormData()
form.append('title', title)
form.append('pageDesc', pageDesc)
form.append('pageUrl', href)
form.append('folderId', folderId)
form.append('pageFile', new Blob([content], { type: 'text/html' }))
if (isNotNil(screenshot)) {
form.append('screenshot', base64ToBlob(screenshot, 'image/webp'))
})

onMessage('get-page-task-list', async () => {
return {
taskList: await getTaskList(),
}
})

onMessage('clear-finished-task-list', async () => {
await clearFinishedTaskList()
})

onMessage('scrape-available', async ({ data: { tabId } }) => {
try {
await request('/pages/upload_new_page', {
method: 'POST',
body: form,
await Browser.scripting.executeScript({
target: { tabId },
func: () => {
console.log('web-archive-scrape-available')
},
})
return { success: true }
return { available: true }
}
catch {
return { success: false }
catch (e) {
return { available: false }
}
})
30 changes: 30 additions & 0 deletions packages/plugin/background/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Browser from 'webextension-polyfill'
import { request } from './background'

async function resetLoginStatus() {
await Browser.storage.local.set({ loginStatus: false })
}

async function checkLoginStatus() {
try {
await request('/auth', {
method: 'POST',
})
await Browser.storage.local.set({ loginStatus: true })
return true
}
catch {
return false
}
}

async function getCacheLoginStatus() {
const { loginStatus } = await Browser.storage.local.get('loginStatus')
return !!loginStatus
}

export {
resetLoginStatus,
checkLoginStatus,
getCacheLoginStatus,
}
147 changes: 147 additions & 0 deletions packages/plugin/background/processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { sendMessage } from 'webext-bridge/background'
import Browser from 'webextension-polyfill'
import { request } from './background'
import type { SingleFileSetting } from '~/utils/singleFile'
import { base64ToBlob } from '~/utils/file'

export interface SeriableSingleFileTask {
uuid: string
status: 'init' | 'scraping' | 'uploading' | 'done' | 'failed'
progress: number
href: string
tabId: number
title: string
pageDesc: string
folderId: string
startTimeStamp: number
endTimeStamp?: number
}

const taskList: SeriableSingleFileTask[] = []

let isInit = false
async function initTask() {
if (isInit) {
return
}

const { tasks } = await Browser.storage.local.get('tasks')
if (tasks) {
tasks.forEach((task: SeriableSingleFileTask) => {
if (task.status !== 'done' && task.status !== 'failed') {
task.status = 'failed'
task.endTimeStamp = Date.now()
}
})
taskList.splice(0, taskList.length, ...tasks)
}
isInit = true
}

Browser.runtime.onStartup.addListener(async () => {
await initTask()
})

async function getTaskList() {
await initTask()
return taskList
}

async function saveTaskList() {
await Browser.storage.local.set({ tasks: taskList })
}

async function clearFinishedTaskList() {
const newTaskList = taskList.filter(task => task.status !== 'done')
taskList.splice(0, taskList.length, ...newTaskList)
await saveTaskList()
}

type CreateTaskOptions = {
tabId: number
pageForm: {
href: string
title: string
pageDesc: string
folderId: string
screenshot?: string
}
singleFileSetting: SingleFileSetting
}

async function scrapePageData(singleFileSetting: SingleFileSetting, tabId: number) {
await Browser.scripting.executeScript({
target: { tabId },
files: ['/lib/single-file.js', '/lib/single-file-extension-core.js'],
})
const { content } = await sendMessage('scrape-page-data', singleFileSetting, `content-script@${tabId}`)
return content
}

async function uploadPageData(pageForm: CreateTaskOptions['pageForm'] & { content: string }) {
const { href, title, pageDesc, folderId, screenshot, content } = pageForm

const form = new FormData()
form.append('title', title)
form.append('pageUrl', href)
form.append('pageDesc', pageDesc)
form.append('folderId', folderId)
form.append('pageFile', new Blob([content], { type: 'text/html' }))
if (screenshot) {
form.append('screenshot', base64ToBlob(screenshot, 'image/webp'))
}
await request('/pages/upload_new_page', {
method: 'POST',
body: form,
})
}

async function createAndRunTask(options: CreateTaskOptions) {
const { singleFileSetting, tabId, pageForm } = options
const { href, title, pageDesc, folderId, screenshot } = pageForm

const uuid = crypto.randomUUID()
const task: SeriableSingleFileTask = {
uuid,
status: 'init',
progress: 0,
tabId,
href,
title,
pageDesc,
folderId,
startTimeStamp: Date.now(),
}

// todo wait refactor, add progress
async function run() {
task.status = 'scraping'
await saveTaskList()
const content = await scrapePageData(singleFileSetting, tabId)

task.status = 'uploading'
await saveTaskList()

await uploadPageData({ content, href, title, pageDesc, folderId, screenshot })
task.status = 'done'
task.endTimeStamp = Date.now()
await saveTaskList()
}

taskList.push(task)
await saveTaskList()
try {
await run()
}
catch (e) {
task.status = 'failed'
task.endTimeStamp = Date.now()
await saveTaskList()
}
}

export {
createAndRunTask,
getTaskList,
clearFinishedTaskList,
}
2 changes: 1 addition & 1 deletion packages/plugin/contentScripts/content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { onMessage, sendMessage } from 'webext-bridge/content-script'
import { onMessage } from 'webext-bridge/content-script'
import { getCurrentPageData } from '~/utils/singleFile'

function createModal() {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/manifest.dev.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "web-page-shelf",
"name": "web-archive",
"author": "Ray-D-Song",
"icons": {
"16": "assets/icon.png",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "web-page-shelf",
"name": "web-archive",
"author": "Ray-D-Song",
"icons": {
"16": "assets/icon.png",
Expand Down
Loading

0 comments on commit d7e5ba0

Please sign in to comment.