├── .gitignore
├── favicon.ico
├── _nuxt
├── fonts
│ ├── 535877f.woff
│ └── 732389d.ttf
├── 318bf53201c4127c79fc.js
├── a84b71f5040faa8705cb.js
├── b46e75617207ae5013d0.js
└── fbd198cfd0f4459e2725.js
├── functions
├── api
│ ├── _middleware.js
│ ├── manage
│ │ ├── logout.js
│ │ ├── login.js
│ │ ├── list.js
│ │ ├── delete
│ │ │ └── [id].js
│ │ ├── check.js
│ │ ├── editName
│ │ │ └── [id].js
│ │ ├── toggleLike
│ │ │ └── [id].js
│ │ ├── block
│ │ │ └── [id].js
│ │ ├── white
│ │ │ └── [id].js
│ │ └── _middleware.js
│ └── bing
│ │ └── wallpaper
│ │ └── index.js
├── file
│ ├── _middleware.js
│ └── [id].js
├── utils
│ └── middleware.js
└── upload.js
├── .github
└── workflows
│ ├── ci-test.yml
│ └── sync.yml
├── package.json
├── music.svg
├── block-img.html
├── whitelist-on.html
├── test
└── pagination.test.js
├── README-EN.md
├── admin-waterfall.html
├── LICENSE
├── bg.svg
├── README.md
├── admin-imgtc.css
├── admin.html
└── admin-imgtc.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/.bin/*
2 | node_modules/.mf/*
3 | .wrangler/*
4 | data/*
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cf-pages/Telegraph-Image/HEAD/favicon.ico
--------------------------------------------------------------------------------
/_nuxt/fonts/535877f.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cf-pages/Telegraph-Image/HEAD/_nuxt/fonts/535877f.woff
--------------------------------------------------------------------------------
/_nuxt/fonts/732389d.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cf-pages/Telegraph-Image/HEAD/_nuxt/fonts/732389d.ttf
--------------------------------------------------------------------------------
/functions/api/_middleware.js:
--------------------------------------------------------------------------------
1 | import { errorHandling, telemetryData } from '../utils/middleware';
2 |
3 | export const onRequest = [errorHandling, telemetryData];
--------------------------------------------------------------------------------
/functions/file/_middleware.js:
--------------------------------------------------------------------------------
1 | import { errorHandling, telemetryData } from '../utils/middleware';
2 |
3 | export const onRequest = [errorHandling, telemetryData];
--------------------------------------------------------------------------------
/.github/workflows/ci-test.yml:
--------------------------------------------------------------------------------
1 | name: CI Test
2 |
3 | on:
4 | pull_request:
5 | branches: [ main ]
6 |
7 | jobs:
8 | test:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v3
13 | - name: Set up Node.js
14 | uses: actions/setup-node@v3
15 | with:
16 | node-version: '20'
17 | - name: Install dependencies
18 | run: npm install
19 | - name: Run tests
20 | run: npm run ci-test
--------------------------------------------------------------------------------
/functions/api/manage/logout.js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | return new Response('Logged out.', { status: 401 });
12 |
13 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "ci-test": "concurrently --kill-others --success first \"npm start\" \"wait-on http://localhost:8080 && mocha --exit\"",
4 | "test": "mocha",
5 | "start": "npx wrangler pages dev ./ --kv \"img_url\" --port 8080 --binding BASIC_USER=admin --binding BASIC_PASS=123 --persist-to ./data"
6 | },
7 | "dependencies": {
8 | "@cloudflare/pages-plugin-sentry": "^1.1.3",
9 | "@sentry/tracing": "^7.114.0"
10 | },
11 | "devDependencies": {
12 | "concurrently": "^8.2.2",
13 | "mocha": "^10.6.0",
14 | "wait-on": "^7.2.0",
15 | "wrangler": "^3.63.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/functions/api/manage/login.js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | //get the request url
12 | const url = new URL(request.url);
13 | //redirect to admin page
14 | return Response.redirect(url.origin+"/admin.html", 302)
15 |
16 | }
--------------------------------------------------------------------------------
/functions/api/manage/list.js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | const { request, env } = context;
3 | const url = new URL(request.url);
4 |
5 | const raw = url.searchParams.get("limit");
6 | let limit = parseInt(raw || "100", 10);
7 | if (!Number.isFinite(limit) || limit <= 0) limit = 100;
8 | if (limit > 1000) limit = 1000;
9 |
10 | const cursor = url.searchParams.get("cursor") || undefined;
11 | const prefix = url.searchParams.get("prefix") || undefined;
12 | const value = await env.img_url.list({ limit, cursor, prefix });
13 |
14 | return new Response(JSON.stringify(value), {
15 | headers: { "Content-Type": "application/json" }
16 | });
17 | }
--------------------------------------------------------------------------------
/functions/api/manage/delete/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | console.log(env)
12 | console.log(params.id)
13 | await env.img_url.delete(params.id);
14 | const info = JSON.stringify(params.id);
15 | return new Response(info);
16 |
17 | }
--------------------------------------------------------------------------------
/functions/api/manage/check.js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | if(typeof context.env.BASIC_USER == "undefined" || context.env.BASIC_USER == null || context.env.BASIC_USER == ""){
12 | return new Response('Not using basic auth.', { status: 200 });
13 | }else{
14 | return new Response('true', { status: 200 });
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/functions/api/manage/editName/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | const { params, env } = context;
3 |
4 | console.log("Request ID:", params.id);
5 |
6 | // 获取元数据
7 | const value = await env.img_url.getWithMetadata(params.id);
8 | console.log("Current metadata:", value);
9 |
10 | // 如果记录不存在
11 | if (!value.metadata) return new Response(`Image metadata not found for ID: ${params.id}`, { status: 404 });
12 |
13 | // 更新文件名
14 | value.metadata.fileName = params.name;
15 | await env.img_url.put(params.id, "", { metadata: value.metadata });
16 |
17 | console.log("Updated metadata:", value.metadata);
18 |
19 | return new Response(JSON.stringify({ success: true, fileName: value.metadata.fileName }), {
20 | headers: { 'Content-Type': 'application/json' },
21 | });
22 | }
--------------------------------------------------------------------------------
/functions/api/manage/toggleLike/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | const { params, env } = context;
3 |
4 | console.log("Request ID:", params.id);
5 |
6 | // 获取元数据
7 | const value = await env.img_url.getWithMetadata(params.id);
8 | console.log("Current metadata:", value);
9 |
10 | // 如果记录不存在
11 | if (!value.metadata) return new Response(`Image metadata not found for ID: ${params.id}`, { status: 404 });
12 |
13 | // 切换 liked 状态并更新
14 | value.metadata.liked = !value.metadata.liked;
15 | await env.img_url.put(params.id, "", { metadata: value.metadata });
16 |
17 | console.log("Updated metadata:", value.metadata);
18 |
19 | return new Response(JSON.stringify({ success: true, liked: value.metadata.liked }), {
20 | headers: { 'Content-Type': 'application/json' },
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/functions/api/bing/wallpaper/index.js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | const res = await fetch(`https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=5`);
12 | const bing_data = await res.json();
13 | const return_data={
14 | "status":true,
15 | "message":"操作成功",
16 | "data": bing_data.images
17 | }
18 | const info = JSON.stringify(return_data);
19 | return new Response(info);
20 |
21 | }
--------------------------------------------------------------------------------
/functions/api/manage/block/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | console.log(env)
12 | console.log(params.id)
13 | //read the metadata
14 | const value = await env.img_url.getWithMetadata(params.id);
15 | console.log(value)
16 | //"metadata":{"TimeStamp":19876541,"ListType":"None","rating_label":"None"}
17 | //change the metadata
18 | value.metadata.ListType = "Block"
19 | await env.img_url.put(params.id,"",{metadata: value.metadata});
20 | const info = JSON.stringify(value.metadata);
21 | return new Response(info);
22 |
23 | }
--------------------------------------------------------------------------------
/functions/api/manage/white/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | console.log(env)
12 | console.log(params.id)
13 | //read the metadata
14 | const value = await env.img_url.getWithMetadata(params.id);
15 | console.log(value)
16 | //"metadata":{"TimeStamp":19876541,"ListType":"None","rating_label":"None"}
17 | //change the metadata
18 | value.metadata.ListType = "White"
19 | await env.img_url.put(params.id,"",{metadata: value.metadata});
20 | const info = JSON.stringify(value.metadata);
21 | return new Response(info);
22 |
23 | }
--------------------------------------------------------------------------------
/music.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/block-img.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | The Image is blocked | Telegraph-Image
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 | 抱歉,当前图片未能通过审查,可能含有不良内容,故无法进行加载。
21 |
22 | Sorry, the current image failed to pass the review and may contain undesirable content, so it cannot be loaded.
23 |
24 |
25 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/whitelist-on.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | WhiteList Mode is ON| Telegraph-Image
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 | 抱歉,当前已开启白名单模式,上传的图片需要审核通过后才能展示,请等待审核通过后再进行访问。
23 |
24 | Sorry, the whitelist mode is currently enabled, the uploaded images need to be audited before they can be displayed, please wait for the audit to be passed before visiting.
25 |
26 |
27 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: Upstream Sync
2 |
3 | permissions:
4 | contents: write
5 |
6 | on:
7 | schedule:
8 | - cron: "0 0 * * *" # every day
9 | workflow_dispatch:
10 |
11 | jobs:
12 | sync_latest_from_upstream:
13 | name: Sync latest commits from upstream repo
14 | runs-on: ubuntu-latest
15 | if: ${{ github.event.repository.fork }}
16 |
17 | steps:
18 | # Step 1: run a standard checkout action
19 | - name: Checkout target repo
20 | uses: actions/checkout@v3
21 |
22 | # Step 2: run the sync action
23 | - name: Sync upstream changes
24 | id: sync
25 | uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
26 | with:
27 | upstream_sync_repo: cf-pages/Telegraph-Image
28 | upstream_sync_branch: main
29 | target_sync_branch: main
30 | target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
31 |
32 | # Set test_mode true to run tests instead of the true action!!
33 | test_mode: false
34 |
35 | - name: Sync check
36 | if: failure()
37 | run: |
38 | echo "[Error] 由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次,详细教程请查看项目README.md "
39 | echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the project README.md for instructions. "
40 | exit 1
41 |
--------------------------------------------------------------------------------
/test/pagination.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 |
3 | describe('KV list pagination', function () {
4 | async function getOnRequest() {
5 | return (await import('../functions/api/manage/list.js')).onRequest;
6 | }
7 |
8 | const sampleKeys = [{ name: 'a' }, { name: 'b' }];
9 | function mockEnv() {
10 | return {
11 | img_url: {
12 | list: ({ limit, cursor }) => {
13 | const start = cursor ? parseInt(cursor, 10) : 0;
14 | const end = Math.min(start + limit, sampleKeys.length);
15 | const keys = sampleKeys.slice(start, end);
16 | const next = end < sampleKeys.length ? String(end) : undefined;
17 | return Promise.resolve({
18 | keys,
19 | list_complete: end >= sampleKeys.length,
20 | cursor: next
21 | });
22 | }
23 | }
24 | };
25 | }
26 |
27 | it('limits results and returns cursor when more data', async function () {
28 | const onRequest = await getOnRequest();
29 | const env = mockEnv();
30 | const request = new Request('https://example.com/api/manage/list?limit=1');
31 | const res = await onRequest({ request, env });
32 | const data = JSON.parse(await res.text());
33 | assert.ok(data.keys.length <= 1);
34 | assert.strictEqual(data.list_complete, false);
35 | assert.ok(data.cursor);
36 | });
37 |
38 | it('second page completes listing', async function () {
39 | const onRequest = await getOnRequest();
40 | const env = mockEnv();
41 | const firstRes = await onRequest({ request: new Request('https://example.com/api/manage/list?limit=1'), env });
42 | const firstData = JSON.parse(await firstRes.text());
43 | const secondRes = await onRequest({ request: new Request(`https://example.com/api/manage/list?cursor=${firstData.cursor}`), env });
44 | const secondData = JSON.parse(await secondRes.text());
45 | assert.strictEqual(secondData.list_complete, true);
46 | assert.ok(!secondData.cursor);
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/_nuxt/318bf53201c4127c79fc.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(data){for(var r,n,l=data[0],f=data[1],d=data[2],i=0,h=[];i {
33 | parsedHeaders[key] = value
34 | //check if the value is empty
35 | if (value.length > 0) {
36 | context.data.sentry.setTag(key, value);
37 | }
38 | });
39 | const CF = JSON.parse(JSON.stringify(context.request.cf));
40 | const parsedCF = {};
41 | for (const key in CF) {
42 | if (typeof CF[key] == "object") {
43 | parsedCF[key] = JSON.stringify(CF[key]);
44 | } else {
45 | parsedCF[key] = CF[key];
46 | if (CF[key].length > 0) {
47 | context.data.sentry.setTag(key, CF[key]);
48 | }
49 | }
50 | }
51 | const data = {
52 | headers: parsedHeaders,
53 | cf: parsedCF,
54 | url: context.request.url,
55 | method: context.request.method,
56 | redirect: context.request.redirect,
57 | }
58 | //get the url path
59 | const urlPath = new URL(context.request.url).pathname;
60 | const hostname = new URL(context.request.url).hostname;
61 | context.data.sentry.setTag("path", urlPath);
62 | context.data.sentry.setTag("url", data.url);
63 | context.data.sentry.setTag("method", context.request.method);
64 | context.data.sentry.setTag("redirect", context.request.redirect);
65 | context.data.sentry.setContext("request", data);
66 | const transaction = context.data.sentry.startTransaction({ name: `${context.request.method} ${hostname}` });
67 | //add the transaction to the context
68 | context.data.transaction = transaction;
69 | return context.next();
70 | } catch (e) {
71 | console.log(e);
72 | } finally {
73 | context.data.transaction.finish();
74 | }
75 | }
76 | return context.next();
77 | }
78 |
79 | export async function traceData(context, span, op, name) {
80 | const data = context.data
81 | if (data.telemetry) {
82 | if (span) {
83 | console.log("span finish")
84 | span.finish();
85 | } else {
86 | console.log("span start")
87 | span = await context.data.transaction.startChild(
88 | { op: op, name: name },
89 | );
90 | }
91 | }
92 | }
93 |
94 | async function fetchSampleRate(context) {
95 | const data = context.data
96 | if (data.telemetry) {
97 | const url = "https://frozen-sentinel.pages.dev/signal/sampleRate.json";
98 | const response = await fetch(url);
99 | const json = await response.json();
100 | return json.rate;
101 | }
102 | }
--------------------------------------------------------------------------------
/README-EN.md:
--------------------------------------------------------------------------------
1 | # Telegraph-Image
2 |
3 | Free Image Hosting solution, Flickr/imgur alternative. Using Cloudflare Pages and Telegraph.
4 |
5 | English|[中文](readme-zh.md)
6 |
7 | Use tg channel/chat for storage
8 |
9 | How to use?
10 |
11 | First, you need to create a new telegram bot to obtain the token and a telegram channel to obtain Chat_ID
12 | ## How to Obtain `Bot_Token` and `Chat_ID` for Telegram
13 |
14 | If you don't have a Telegram account yet, please create one first. Then, follow these steps to get the `Bot_Token` and `Chat_ID`:
15 |
16 | 1. **Get the `Bot_Token`**
17 | - In Telegram, send the command `/newbot` to [@BotFather](https://t.me/BotFather), and follow the prompts to input your bot's name and username. Once successfully created, you will receive a `Bot_Token`, which is used to interact with the Telegram API.
18 |
19 | 2. **Set the bot as a channel administrator**
20 | - Create a new channel and, after entering the channel, go to channel settings. Add the bot you just created as a channel administrator, so it can send messages.
21 |
22 | 3. **Get the `Chat_ID`**
23 | - Use [@GetTheirIDBot](https://t.me/GetTheirIDBot) to get your channel ID. Send a message to this bot and follow the instructions to receive your `Chat_ID` (the ID of your channel).
24 |
25 | ## Deployment
26 |
27 | ### Preparation
28 |
29 | The only thing you need to prepare in advance is a Cloudflare account
30 |
31 | ### Step by Step Instruction
32 |
33 | 3 simple steps to deploy this project and have your own image hosting
34 |
35 | 1.Fork this repository (Note: In order to make this work. You have to using Git or Wrangler CLI to deploy this project. [Document](https://developers.cloudflare.com/pages/functions/get-started/#deploy-your-function))
36 |
37 | 2.Open the Cloudflare Dashboard, enter the Pages management page, choose to create a project, then choose `Connecting to the Git Provider`
38 |
39 | 
40 |
41 | 3. Follow the prompts on the page to enter the project name, select the git repository you need to connect to, then click `Deploy`
42 |
43 | ## Features
44 |
45 | 1. Unlimited number of images stored, you can upload an unlimited number of images
46 |
47 | 2. No need to buy a server, hosted on Cloudflare's network, when the use does not exceed Cloudflare's free quota, completely free
48 |
49 | 3. No need to buy a domain name, you can use the free second-level domain name `*.pages.dev` provided by Cloudflare Pages, and also support binding custom domain names
50 |
51 | 4. Support image review API, can be opened as needed, after opening undesirable images will be automatically blocked, no longer loaded
52 |
53 | ### Add custom domains
54 |
55 | Inside the custom domain of pages, bind the domain name that exists in your Cloudflare account, the domain name hosted in cloudflare, will automatically modify the dns record
56 | 
57 |
58 | ### Setup image review API
59 |
60 | 1. Please go to https://moderatecontent.com/ to register and get a free API key for reviewing image content
61 |
62 | 2. Open the settings of Cloudflare Pages, click `Settings`, `Environment Variables`, `Add Environment Variables` in turn
63 |
64 | 3. Add a `variable` name as `ModerateContentApiKey`, `value` as the `API key` you just got in the first step, click `Save` to
65 |
66 | Note: Since the changes will take effect on the next deployment, you may need to go to the `Deploy` page and redeploy the project
67 |
68 | When image review is enabled, the first time image load will be slow because it takes time to review, but the subsequent image load will not be affected due to the existence of cache
69 | 
70 |
71 | ### Limitations
72 |
73 | 1. Since the image files are actually stored in Telegraph, Telegraph limits the size of uploaded images to a maximum of 5MB
74 |
75 | 2. Due to the use of Cloudflare's network, the loading speed of images may not be guaranteed in some areas.
76 |
77 | 3. The free version of Cloudflare Function is limited to 100,000 requests per day (i.e. the total number of uploads or loads of images cannot exceed 100,000), if this is exceeded, you may need to choose to purchase the paid package of Cloudflare Function.
78 |
79 | ### Thanks
80 |
81 | Ideas and code provided by Hostloc @feixiang and @乌拉擦
82 |
--------------------------------------------------------------------------------
/functions/api/manage/_middleware.js:
--------------------------------------------------------------------------------
1 | async function errorHandling(context) {
2 | try {
3 | return await context.next();
4 | } catch (err) {
5 | return new Response(`${err.message}\n${err.stack}`, { status: 500 });
6 | }
7 | }
8 |
9 | function basicAuthentication(request) {
10 | const Authorization = request.headers.get('Authorization');
11 |
12 | const [scheme, encoded] = Authorization.split(' ');
13 |
14 | // The Authorization header must start with Basic, followed by a space.
15 | if (!encoded || scheme !== 'Basic') {
16 | throw new BadRequestException('Malformed authorization header.');
17 | }
18 |
19 | // Decodes the base64 value and performs unicode normalization.
20 | // @see https://datatracker.ietf.org/doc/html/rfc7613#section-3.3.2 (and #section-4.2.2)
21 | // @see https://dev.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
22 | const buffer = Uint8Array.from(atob(encoded), character => character.charCodeAt(0));
23 | const decoded = new TextDecoder().decode(buffer).normalize();
24 |
25 | // The username & password are split by the first colon.
26 | //=> example: "username:password"
27 | const index = decoded.indexOf(':');
28 |
29 | // The user & password are split by the first colon and MUST NOT contain control characters.
30 | // @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> "CTL = %x00-1F / %x7F")
31 | if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) {
32 | throw new BadRequestException('Invalid authorization value.');
33 | }
34 |
35 | return {
36 | user: decoded.substring(0, index),
37 | pass: decoded.substring(index + 1),
38 | };
39 | }
40 |
41 | function UnauthorizedException(reason) {
42 | return new Response(reason, {
43 | status: 401,
44 | statusText: 'Unauthorized',
45 | headers: {
46 | 'Content-Type': 'text/plain;charset=UTF-8',
47 | // Disables caching by default.
48 | 'Cache-Control': 'no-store',
49 | // Returns the "Content-Length" header for HTTP HEAD requests.
50 | 'Content-Length': reason.length,
51 | },
52 | });
53 | }
54 |
55 | function BadRequestException(reason) {
56 | return new Response(reason, {
57 | status: 400,
58 | statusText: 'Bad Request',
59 | headers: {
60 | 'Content-Type': 'text/plain;charset=UTF-8',
61 | // Disables caching by default.
62 | 'Cache-Control': 'no-store',
63 | // Returns the "Content-Length" header for HTTP HEAD requests.
64 | 'Content-Length': reason.length,
65 | },
66 | });
67 | }
68 |
69 |
70 | function authentication(context) {
71 | //context.env.BASIC_USER="admin"
72 | //context.env.BASIC_PASS="admin"
73 | //check if the env variables Disable_Dashboard are set
74 | if (typeof context.env.img_url == "undefined" || context.env.img_url == null || context.env.img_url == "") {
75 | return new Response('Dashboard is disabled. Please bind a KV namespace to use this feature.', { status: 200 });
76 | }
77 |
78 | console.log(context.env.BASIC_USER)
79 | if(typeof context.env.BASIC_USER == "undefined" || context.env.BASIC_USER == null || context.env.BASIC_USER == ""){
80 | return context.next();
81 | }else{
82 | if (context.request.headers.has('Authorization')) {
83 | // Throws exception when authorization fails.
84 | const { user, pass } = basicAuthentication(context.request);
85 |
86 |
87 | if (context.env.BASIC_USER !== user || context.env.BASIC_PASS !== pass) {
88 | return UnauthorizedException('Invalid credentials.');
89 | }else{
90 | return context.next();
91 | }
92 |
93 | } else {
94 | return new Response('You need to login.', {
95 | status: 401,
96 | headers: {
97 | // Prompts the user for credentials.
98 | 'WWW-Authenticate': 'Basic realm="my scope", charset="UTF-8"',
99 | },
100 | });
101 | }
102 | }
103 |
104 | }
105 |
106 | export const onRequest = [errorHandling, authentication];
--------------------------------------------------------------------------------
/admin-waterfall.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Waterfall
7 |
59 |
60 |
61 |
62 | 加载更多
63 |
64 |
65 |
66 |
91 |
92 |
149 |
--------------------------------------------------------------------------------
/functions/upload.js:
--------------------------------------------------------------------------------
1 | import { errorHandling, telemetryData } from "./utils/middleware";
2 |
3 | export async function onRequestPost(context) {
4 | const { request, env } = context;
5 |
6 | try {
7 | const clonedRequest = request.clone();
8 | const formData = await clonedRequest.formData();
9 |
10 | await errorHandling(context);
11 | telemetryData(context);
12 |
13 | const uploadFile = formData.get('file');
14 | if (!uploadFile) {
15 | throw new Error('No file uploaded');
16 | }
17 |
18 | const fileName = uploadFile.name;
19 | const fileExtension = fileName.split('.').pop().toLowerCase();
20 |
21 | const telegramFormData = new FormData();
22 | telegramFormData.append("chat_id", env.TG_Chat_ID);
23 |
24 | // 根据文件类型选择合适的上传方式
25 | let apiEndpoint;
26 | if (uploadFile.type.startsWith('image/')) {
27 | telegramFormData.append("photo", uploadFile);
28 | apiEndpoint = 'sendPhoto';
29 | } else if (uploadFile.type.startsWith('audio/')) {
30 | telegramFormData.append("audio", uploadFile);
31 | apiEndpoint = 'sendAudio';
32 | } else if (uploadFile.type.startsWith('video/')) {
33 | telegramFormData.append("video", uploadFile);
34 | apiEndpoint = 'sendVideo';
35 | } else {
36 | telegramFormData.append("document", uploadFile);
37 | apiEndpoint = 'sendDocument';
38 | }
39 |
40 | const result = await sendToTelegram(telegramFormData, apiEndpoint, env);
41 |
42 | if (!result.success) {
43 | throw new Error(result.error);
44 | }
45 |
46 | const fileId = getFileId(result.data);
47 |
48 | if (!fileId) {
49 | throw new Error('Failed to get file ID');
50 | }
51 |
52 | // 将文件信息保存到 KV 存储
53 | if (env.img_url) {
54 | await env.img_url.put(`${fileId}.${fileExtension}`, "", {
55 | metadata: {
56 | TimeStamp: Date.now(),
57 | ListType: "None",
58 | Label: "None",
59 | liked: false,
60 | fileName: fileName,
61 | fileSize: uploadFile.size,
62 | }
63 | });
64 | }
65 |
66 | return new Response(
67 | JSON.stringify([{ 'src': `/file/${fileId}.${fileExtension}` }]),
68 | {
69 | status: 200,
70 | headers: { 'Content-Type': 'application/json' }
71 | }
72 | );
73 | } catch (error) {
74 | console.error('Upload error:', error);
75 | return new Response(
76 | JSON.stringify({ error: error.message }),
77 | {
78 | status: 500,
79 | headers: { 'Content-Type': 'application/json' }
80 | }
81 | );
82 | }
83 | }
84 |
85 | function getFileId(response) {
86 | if (!response.ok || !response.result) return null;
87 |
88 | const result = response.result;
89 | if (result.photo) {
90 | return result.photo.reduce((prev, current) =>
91 | (prev.file_size > current.file_size) ? prev : current
92 | ).file_id;
93 | }
94 | if (result.document) return result.document.file_id;
95 | if (result.video) return result.video.file_id;
96 | if (result.audio) return result.audio.file_id;
97 |
98 | return null;
99 | }
100 |
101 | async function sendToTelegram(formData, apiEndpoint, env, retryCount = 0) {
102 | const MAX_RETRIES = 2;
103 | const apiUrl = `https://api.telegram.org/bot${env.TG_Bot_Token}/${apiEndpoint}`;
104 |
105 | try {
106 | const response = await fetch(apiUrl, { method: "POST", body: formData });
107 | const responseData = await response.json();
108 |
109 | if (response.ok) {
110 | return { success: true, data: responseData };
111 | }
112 |
113 | // 图片上传失败时转为文档方式重试
114 | if (retryCount < MAX_RETRIES && apiEndpoint === 'sendPhoto') {
115 | console.log('Retrying image as document...');
116 | const newFormData = new FormData();
117 | newFormData.append('chat_id', formData.get('chat_id'));
118 | newFormData.append('document', formData.get('photo'));
119 | return await sendToTelegram(newFormData, 'sendDocument', env, retryCount + 1);
120 | }
121 |
122 | return {
123 | success: false,
124 | error: responseData.description || 'Upload to Telegram failed'
125 | };
126 | } catch (error) {
127 | console.error('Network error:', error);
128 | if (retryCount < MAX_RETRIES) {
129 | await new Promise(resolve => setTimeout(resolve, 1000 * (retryCount + 1)));
130 | return await sendToTelegram(formData, apiEndpoint, env, retryCount + 1);
131 | }
132 | return { success: false, error: 'Network error occurred' };
133 | }
134 | }
--------------------------------------------------------------------------------
/functions/file/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | const {
3 | request,
4 | env,
5 | params,
6 | } = context;
7 |
8 | const url = new URL(request.url);
9 | let fileUrl = 'https://telegra.ph/' + url.pathname + url.search
10 | if (url.pathname.length > 39) { // Path length > 39 indicates file uploaded via Telegram Bot API
11 | const formdata = new FormData();
12 | formdata.append("file_id", url.pathname);
13 |
14 | const requestOptions = {
15 | method: "POST",
16 | body: formdata,
17 | redirect: "follow"
18 | };
19 | // /file/AgACAgEAAxkDAAMDZt1Gzs4W8dQPWiQJxO5YSH5X-gsAAt-sMRuWNelGOSaEM_9lHHgBAAMCAANtAAM2BA.png
20 | //get the AgACAgEAAxkDAAMDZt1Gzs4W8dQPWiQJxO5YSH5X-gsAAt-sMRuWNelGOSaEM_9lHHgBAAMCAANtAAM2BA
21 | console.log(url.pathname.split(".")[0].split("/")[2])
22 | const filePath = await getFilePath(env, url.pathname.split(".")[0].split("/")[2]);
23 | console.log(filePath)
24 | fileUrl = `https://api.telegram.org/file/bot${env.TG_Bot_Token}/${filePath}`;
25 | }
26 |
27 | const response = await fetch(fileUrl, {
28 | method: request.method,
29 | headers: request.headers,
30 | body: request.body,
31 | });
32 |
33 | // If the response is OK, proceed with further checks
34 | if (!response.ok) return response;
35 |
36 | // Log response details
37 | console.log(response.ok, response.status);
38 |
39 | // Allow the admin page to directly view the image
40 | const isAdmin = request.headers.get('Referer')?.includes(`${url.origin}/admin`);
41 | if (isAdmin) {
42 | return response;
43 | }
44 |
45 | // Check if KV storage is available
46 | if (!env.img_url) {
47 | console.log("KV storage not available, returning image directly");
48 | return response; // Directly return image response, terminate execution
49 | }
50 |
51 | // The following code executes only if KV is available
52 | let record = await env.img_url.getWithMetadata(params.id);
53 | if (!record || !record.metadata) {
54 | // Initialize metadata if it doesn't exist
55 | console.log("Metadata not found, initializing...");
56 | record = {
57 | metadata: {
58 | ListType: "None",
59 | Label: "None",
60 | TimeStamp: Date.now(),
61 | liked: false,
62 | fileName: params.id,
63 | fileSize: 0,
64 | }
65 | };
66 | await env.img_url.put(params.id, "", { metadata: record.metadata });
67 | }
68 |
69 | const metadata = {
70 | ListType: record.metadata.ListType || "None",
71 | Label: record.metadata.Label || "None",
72 | TimeStamp: record.metadata.TimeStamp || Date.now(),
73 | liked: record.metadata.liked !== undefined ? record.metadata.liked : false,
74 | fileName: record.metadata.fileName || params.id,
75 | fileSize: record.metadata.fileSize || 0,
76 | };
77 |
78 | // Handle based on ListType and Label
79 | if (metadata.ListType === "White") {
80 | return response;
81 | } else if (metadata.ListType === "Block" || metadata.Label === "adult") {
82 | const referer = request.headers.get('Referer');
83 | const redirectUrl = referer ? "https://static-res.pages.dev/teleimage/img-block-compressed.png" : `${url.origin}/block-img.html`;
84 | return Response.redirect(redirectUrl, 302);
85 | }
86 |
87 | // Check if WhiteList_Mode is enabled
88 | if (env.WhiteList_Mode === "true") {
89 | return Response.redirect(`${url.origin}/whitelist-on.html`, 302);
90 | }
91 |
92 | // If no metadata or further actions required, moderate content and add to KV if needed
93 | if (env.ModerateContentApiKey) {
94 | try {
95 | console.log("Starting content moderation...");
96 | const moderateUrl = `https://api.moderatecontent.com/moderate/?key=${env.ModerateContentApiKey}&url=https://telegra.ph${url.pathname}${url.search}`;
97 | const moderateResponse = await fetch(moderateUrl);
98 |
99 | if (!moderateResponse.ok) {
100 | console.error("Content moderation API request failed: " + moderateResponse.status);
101 | } else {
102 | const moderateData = await moderateResponse.json();
103 | console.log("Content moderation results:", moderateData);
104 |
105 | if (moderateData && moderateData.rating_label) {
106 | metadata.Label = moderateData.rating_label;
107 |
108 | if (moderateData.rating_label === "adult") {
109 | console.log("Content marked as adult, saving metadata and redirecting");
110 | await env.img_url.put(params.id, "", { metadata });
111 | return Response.redirect(`${url.origin}/block-img.html`, 302);
112 | }
113 | }
114 | }
115 | } catch (error) {
116 | console.error("Error during content moderation: " + error.message);
117 | // Moderation failure should not affect user experience, continue processing
118 | }
119 | }
120 |
121 | // Only save metadata if content is not adult content
122 | // Adult content cases are already handled above and will not reach this point
123 | console.log("Saving metadata");
124 | await env.img_url.put(params.id, "", { metadata });
125 |
126 | // Return file content
127 | return response;
128 | }
129 |
130 | async function getFilePath(env, file_id) {
131 | try {
132 | const url = `https://api.telegram.org/bot${env.TG_Bot_Token}/getFile?file_id=${file_id}`;
133 | const res = await fetch(url, {
134 | method: 'GET',
135 | });
136 |
137 | if (!res.ok) {
138 | console.error(`HTTP error! status: ${res.status}`);
139 | return null;
140 | }
141 |
142 | const responseData = await res.json();
143 | const { ok, result } = responseData;
144 |
145 | if (ok && result) {
146 | return result.file_path;
147 | } else {
148 | console.error('Error in response data:', responseData);
149 | return null;
150 | }
151 | } catch (error) {
152 | console.error('Error fetching file path:', error.message);
153 | return null;
154 | }
155 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/bg.svg:
--------------------------------------------------------------------------------
1 | { }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Telegraph-Image
2 |
3 | 免费图片托管解决方案,Flickr/imgur 替代品。使用 Cloudflare Pages 和 Telegraph。
4 |
5 | [English](README-EN.md)|中文
6 |
7 | > [!IMPORTANT]
8 | >
9 | > 由于原有的Telegraph API接口被官方关闭,需要将上传渠道切换至Telegram Channel,请按照文档中的部署要求设置`TG_Bot_Token`和`TG_Chat_ID`,否则将无法正常使用上传功能。
10 |
11 | ## 如何获取Telegram的`Bot_Token`和`Chat_ID`
12 |
13 | 如果您还没有Telegram账户,请先创建一个。接着,按照以下步骤操作以获取`BOT_TOKEN`和`CHAT_ID`:
14 |
15 | 1. **获取`Bot_Token`**
16 | - 在Telegram中,向[@BotFather](https://t.me/BotFather)发送命令`/newbot`,根据提示依次输入您的机器人名称和用户名。成功创建机器人后,您将会收到一个`BOT_TOKEN`,用于与Telegram API进行交互。
17 |
18 | 
19 |
20 | 2. **设置机器人为频道管理员**
21 | - 创建一个新的频道(Channel),进入该频道后,选择频道设置。将刚刚创建的机器人添加为频道管理员,这样机器人才能发送消息。
22 |
23 | 
24 |
25 | 
26 |
27 |
28 | 3. **获取`Chat_ID`**
29 | - 通过[@VersaToolsBot](https://t.me/VersaToolsBot)获取您的频道ID。向该机器人发送消息,按照指示操作,最后您将得到`CHAT_ID`(即频道的ID)。
30 | - 或者通过[@GetTheirIDBot](https://t.me/GetTheirIDBot)获取您的频道ID。向该机器人发送消息,按照指示操作,最后您将得到`CHAT_ID`(即频道的ID)。
31 |
32 | 
33 |
34 | 最后去Cloudflare Pages后台设置相关的环境变量(注:修改环境变量后,需要重新部署才能生效)
35 | | 环境变量 | 示例值 | 说明 |
36 | |-----------------|---------------------------|----------------------------------------------------------------------------------------|
37 | | `TG_Bot_Token` | `123468:AAxxxGKrn5` | 从[@BotFather](https://t.me/BotFather)获取的Telegram Bot Token。 |
38 | | `TG_Chat_ID` | `-1234567` | 频道的ID,确保TG Bot是该频道或群组的管理员。 |
39 |
40 | ## 如何部署
41 |
42 | ### 提前准备
43 |
44 | 你唯一需要提前准备的就是一个 Cloudflare 账户 (如果需要在自己的服务器上部署,不依赖 Cloudflare,可参考[#46](https://github.com/cf-pages/Telegraph-Image/issues/46) )
45 |
46 | ### 手把手教程
47 |
48 | 简单 3 步,即可部署本项目,拥有自己的图床
49 |
50 | 1.Fork 本仓库 (注意:必须使用 Git 或者 Wrangler 命令行工具部署后才能正常使用,[文档](https://developers.cloudflare.com/pages/functions/get-started/#deploy-your-function))
51 |
52 | 2.打开 Cloudflare Dashboard,进入 Pages 管理页面,选择创建项目,选择`连接到 Git 提供程序`
53 |
54 | 
55 |
56 | 3. 按照页面提示输入项目名称,选择需要连接的 git 仓库,点击`部署站点`即可完成部署
57 |
58 | ## 特性
59 |
60 | 1.无限图片储存数量,你可以上传不限数量的图片
61 |
62 | 2.无需购买服务器,托管于 Cloudflare 的网络上,当使用量不超过 Cloudflare 的免费额度时,完全免费
63 |
64 | 3.无需购买域名,可以使用 Cloudflare Pages 提供的`*.pages.dev`的免费二级域名,同时也支持绑定自定义域名
65 |
66 | 4.支持图片审查 API,可根据需要开启,开启后不良图片将自动屏蔽,不再加载
67 |
68 | 5.支持后台图片管理,可以对上传的图片进行在线预览,添加白名单,黑名单等操作
69 |
70 | ### 绑定自定义域名
71 |
72 | 在 pages 的自定义域里面,绑定 cloudflare 中存在的域名,在 cloudflare 托管的域名,自动会修改 dns 记录
73 | 
74 |
75 | ### 开启图片审查
76 |
77 | 1.请前往https://moderatecontent.com/ 注册并获得一个免费的用于审查图像内容的 API key
78 |
79 | 2.打开 Cloudflare Pages 的管理页面,依次点击`设置`,`环境变量`,`添加环境变量`
80 |
81 | 3.添加一个`变量名称`为`ModerateContentApiKey`,`值`为你刚刚第一步获得的`API key`,点击`保存`即可
82 |
83 | 注意:由于所做的更改将在下次部署时生效,你或许还需要进入`部署`页面,重新部署一下该本项目
84 |
85 | 开启图片审查后,因为审查需要时间,首次的图片加载将会变得缓慢,之后的图片加载由于存在缓存,并不会受到影响
86 | 
87 |
88 | ### 限制
89 |
90 | 1.由于图片文件实际存储于 Telegraph,Telegraph 限制上传的图片大小最大为 5MB
91 |
92 | 2.由于使用 Cloudflare 的网络,图片的加载速度在某些地区可能得不到保证
93 |
94 | 3.Cloudflare Function 免费版每日限制 100,000 个请求(即上传或是加载图片的总次数不能超过 100,000 次)如超过可能需要选择购买 Cloudflare Function 的付费套餐,如开启图片管理功能还会存在 KV 操作数量的限制,如超过需购买付费套餐
95 |
96 | ### 感谢
97 |
98 | Hostloc @feixiang 和@乌拉擦 提供的思路和代码
99 |
100 | ## 更新日志
101 | 2024 年 7 月 6 日--后台管理页面更新
102 |
103 | - 支持两个新的管理页面视图(网格视图和瀑布流)
104 |
105 | 1、网格视图,感谢@DJChanahCJD 提交的代码
106 | 支持批量删除/复制链接
107 | 支持按时间倒序排序
108 | 支持分页功能
109 | 
110 | 2、瀑布流视图,感谢@panther125 提交的代码
111 | 
112 |
113 | - 添加自动更新支持
114 |
115 | 现在fork的项目能够自动和上游仓库同步最新的更改,自动实装最新的项目功能,感谢 @bian2022
116 |
117 | 打开自动更新步骤:
118 | 当你 fork 项目之后,由于 Github 的限制,需要手动去你 fork 后的项目的 Actions 页面启用 Workflows,并启用 Upstream Sync Action,启用之后即可开启每小时定时自动更新:
119 | 
120 | 
121 | `如果你遇到了 Upstream Sync 执行错误,请手动 Sync Fork 一次!`
122 |
123 | 手动更新代码
124 |
125 | 如果你想让手动立即更新,可以查看 [Github 的文档](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) 了解如何让 fork 的项目与上游代码同步。
126 |
127 | 你可以 star/watch 本项目或者 follow 作者来及时获得新功能更新通知。
128 | - 添加远端遥测
129 |
130 | 可通过添加`disable_telemetry`环境变量退出遥测
131 |
132 | 2023 年 1 月 18 日--图片管理功能更新
133 |
134 | 1、支持图片管理功能,默认是关闭的,如需开启请部署完成后前往后台依次点击`设置`->`函数`->`KV 命名空间绑定`->`编辑绑定`->`变量名称`填写:`img_url` `KV 命名空间` 选择你提前创建好的 KV 储存空间,开启后访问 http(s)://你的域名/admin 即可打开后台管理页面
135 | | 变量名称 | KV 命名空间 |
136 | | ----------- | ----------- |
137 | | img_url | 选择提前创建好的 KV 储存空间 |
138 |
139 | 
140 | 
141 |
142 | 2、后台管理页面新增登录验证功能,默认也是关闭的,如需开启请部署完成后前往后台依次点击`设置`->`环境变量`->`为生产环境定义变量`->`编辑变量` 添加如下表格所示的变量即可开启登录验证
143 | | 变量名称 | 值 |
144 | | ----------- | ----------- |
145 | |BASIC_USER = | <后台管理页面登录用户名称>|
146 | |BASIC_PASS = | <后台管理页面登录用户密码>|
147 |
148 | 
149 |
150 | 当然你也可以不设置这两个值,这样访问后台管理页面时将无需验证,直接跳过登录步骤,这一设计使得你可以结合 Cloudflare Access 进行使用,实现支持邮件验证码登录,Microsoft 账户登录,Github 账户登录等功能,能够与你域名上原有的登录方式所集成,无需再次记忆多一组后台的账号密码,添加 Cloudflare Access 的方式请参考官方文档,注意需要保护路径包括/admin 以及 /api/manage/\*
151 |
152 | 3、新增图片总数量统计
153 | 当开启图片管理功能后,可在后台顶部查看记录中的图片数量
154 |
155 | 
156 |
157 | 4、新增图片文件名搜索
158 | 当开启图片管理功能后,可在后台搜索框使用图片文件名称,快速搜索定位需要管理的图片
159 |
160 | 
161 |
162 | 5、新增图片状态显示
163 | 当开启图片管理功能后,可在后台查看图片当前的状态{ "ListType": "None", "TimeStamp": 1673984678274 }
164 | ListType 代表图片当前是否在黑白名单当中,None 则表示既不在黑名单中也不在白名单中,White 表示在在白名单中,Block 表示在黑名单中,TimeStamp 为图片首次加载的时间戳,如开启的图片审查 API,则这里还会显示图片审查的结果用 Label 标识
165 |
166 | 
167 |
168 | 6、新增黑名单功能
169 | 当开启图片管理功能后,可在后台手动为图片加入黑名单,加入黑名单的图片将无法正常加载
170 |
171 | 
172 |
173 | 7、新增白名单功能
174 | 当开启图片管理功能后,可在后台手动为图片加入白名单,加入白名单的图片无论如何都会正常加载,可绕过图片审查 API 的结果
175 |
176 | 
177 |
178 | 8、新增记录删除功能
179 | 当开启图片管理功能后,可在后台手动删除图片记录,即不再后台显示该图片,除非有人再次上传并加载该图片,注意由于图片储存在 telegraph 的服务器上,我们无法删除上传的原始图片,只能通过上述第 6 点的黑名单功能屏蔽图片的加载
180 |
181 | 9、新增程序运行模式:白名单模式
182 | 当开启图片管理功能后,除了默认模式外,这次更新还新增了一项新的运行模式,在该模式下,只有被添加进白名单的图片才会被加载,上传的图片需要审核通过后才能展示,最大程度的防止不良图片的加载,如需开启请设置环境变量:WhiteList_Mode=="true"
183 |
184 | 10、新增后台图片预览功能
185 | 当开启图片管理功能后,可在后台预览通过你的域名加载过的图片,点击图片可以进行放大,缩小,旋转等操作
186 |
187 | 
188 |
189 | ## 已经部署了的,如何更新?
190 |
191 | 其实更新非常简单,只需要参照上面的更新内容,先进入到 Cloudflare Pages 后台,把需要使用的环境变量提前设置好并绑定上 KV 命名空间,然后去到 Github 你之前 fork 过的仓库依次选择`Sync fork`->`Update branch`即可,稍等一会,Cloudflare Pages 那边检测到你的仓库更新了之后就会自动部署最新的代码了
192 |
193 | ## 一些限制:
194 |
195 | Cloudflare KV 每天只有 1000 次的免费写入额度,每有一张新的图片加载都会占用该写入额度,如果超过该额度,图片管理后台将无法记录新加载的图片
196 |
197 | 每天最多 100,000 次免费读取操作,图片每加载一次都会占用该额度(在没有缓存的情况下,如果你的域名在 Cloudflare 开启了缓存,当缓存未命中时才会占用该额度),超过黑白名单等功能可能会失效
198 |
199 | 每天最多 1,000 次免费删除操作,每有一条图片记录都会占用该额度,超过将无法删除图片记录
200 |
201 | 每天最多 1,000 次免费列出操作,每打开或刷新一次后台/admin 都会占用该额度,超过将进行后台图片管理
202 |
203 | 绝大多数情况下,该免费额度都基本够用,并且可以稍微超出一点,不是已超出就立马停用,且每项额度单独计算,某项操作超出免费额度后只会停用该项操作,不影响其他的功能,即即便我的免费写入额度用完了,我的读写功能不受影响,图片能够正常加载,只是不能在图片管理后台看到新的图片了。
204 |
205 | 如果你的免费额度不够用,可以自行向 Cloudflare 购买 Cloudflare Workers 的付费版本,每月$5 起步,按量收费,没有上述额度限制
206 |
207 | 另外针对环境变量所做的更改将在下次部署时生效,如更改了`环境变量`,针对某项功能进行了开启或关闭,请记得重新部署。
208 |
209 | 
210 |
211 | ### Sponsorship
212 |
213 | This project is tested with BrowserStack.
214 |
215 | This project is support by [Cloudflare](https://www.cloudflare.com/).
216 |
--------------------------------------------------------------------------------
/admin-imgtc.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: linear-gradient(90deg, #ffd7e4 0%, #c8f1ff 100%);
3 | font-family: 'Arial', sans-serif;
4 | color: #333;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | .header-content {
10 | position: fixed;
11 | top: 0;
12 | left: 1%;
13 | right: 1%;
14 | z-index: 999;
15 | height: clamp(40px, 8vh, 60px);
16 | display: flex;
17 | align-items: center;
18 | padding: 10px 20px;
19 | background-color: rgba(255, 255, 255, 0.75);
20 | -webkit-backdrop-filter: blur(10px);
21 | backdrop-filter: blur(10px);
22 | border-bottom: 1px solid rgba(0, 0, 0, 0.1);
23 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
24 | transition: background-color 0.5s ease, box-shadow 0.5s ease;
25 | border-bottom-left-radius: 10px;
26 | border-bottom-right-radius: 10px;
27 | }
28 |
29 | .header-content:hover {
30 | background-color: rgba(255, 255, 255, 0.85);
31 | box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2);
32 | }
33 |
34 | .title {
35 | font-size: clamp(1.2em, 2vw, 1.8em);
36 | font-weight: bold;
37 | cursor: pointer;
38 | transition: color 0.3s ease;
39 | margin-right: 4px;
40 | color: #333;
41 | }
42 |
43 | .title:hover {
44 | color: #B39DDB; /* 使用柔和的淡紫色 */
45 | }
46 |
47 | .search-card {
48 | margin-left: auto;
49 | margin-right: 16px;
50 | }
51 |
52 | .stats {
53 | display: flex;
54 | align-items: center;
55 | cursor: pointer;
56 | font-size: clamp(0.9em, 1.5vw, 1.2em);
57 | background: rgba(255, 255, 255, 0.9);
58 | margin-right: 8px;
59 | padding: 2px 8px;
60 | border-radius: 12px;
61 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
62 | transition: all 0.3s ease;
63 | color: #333;
64 | }
65 |
66 | .stats:hover {
67 | background-color: #f0eaf8; /* 柔和的淡紫色 */
68 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
69 | transform: scale(1.02);
70 | color: #B39DDB;
71 | }
72 |
73 | .upload-icon {
74 | margin-right: 10px;
75 | font-size: clamp(1.2em, 1.5vw, 1.6em);
76 | transition: color 0.3s ease, transform 0.3s ease, background-color 0.3s ease;
77 | color: inherit;
78 | cursor: pointer;
79 | border-radius: 50%;
80 | padding: 8px;
81 | background-color: rgba(179, 157, 219, 0.15);
82 | border: 1px solid transparent;
83 | }
84 |
85 | .header-content .actions {
86 | display: flex;
87 | align-items: center;
88 | }
89 |
90 | .header-content .actions i {
91 | font-size: clamp(1.2em, 1.5vw, 1.6em);
92 | cursor: pointer;
93 | transition: color 0.3s, transform 0.3s;
94 | color: #333;
95 | margin: 0 8px;
96 | }
97 |
98 | .header-content .actions i:hover {
99 | color: #B39DDB;
100 | transform: scale(1.1);
101 | }
102 |
103 | .header-content .actions .el-dropdown-link i {
104 | color: #333;
105 | }
106 |
107 | .header-content .actions .disabled {
108 | color: #bbb;
109 | pointer-events: none;
110 | }
111 |
112 | .header-content .actions .enabled {
113 | color: #B39DDB; /* 使用柔和的淡紫色 */
114 | }
115 |
116 | .search-card .el-input__inner {
117 | border-radius: 20px;
118 | width: clamp(200px, 25vw, 300px);
119 | height: clamp(30px, 5vh, 40px);
120 | font-size: 1.2em;
121 | border: none;
122 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
123 | transition: width 0.3s;
124 | }
125 |
126 | .search-card .el-input__inner:focus {
127 | width: clamp(250px, 30vw, 400px);
128 | }
129 |
130 | .main-container {
131 | display: flex;
132 | flex-direction: column;
133 | margin-top: 20px;
134 | padding: 20px;
135 | min-height: calc(100vh - 80px);
136 | }
137 |
138 | .content {
139 | display: grid;
140 | grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
141 | gap: 20px;
142 | padding: 10px;
143 | flex-grow: 1;
144 | }
145 |
146 | /* 图片卡片样式 */
147 | .image-card {
148 | width: 100%;
149 | aspect-ratio: 4 / 3;
150 | background: rgba(255, 255, 255, 0.6) !important;
151 | border-radius: 8px;
152 | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
153 | overflow: hidden;
154 | position: relative;
155 | object-fit: cover;
156 | transition: transform 0.3s ease;
157 | border: none;
158 | }
159 |
160 | .image-card:hover {
161 | transform: scale(1.02);
162 | cursor: pointer;
163 | }
164 |
165 | .image-card .el-checkbox {
166 | position: absolute;
167 | top: 10px;
168 | right: 10px;
169 | transform: scale(1.5);
170 | z-index: 10;
171 | margin: 0; /* 重要:移除默认边距 */
172 | padding: 0; /* 重要:移除默认内边距 */
173 | }
174 |
175 | .el-image {
176 | width: 100%;
177 | height: 100%;
178 | display: block;
179 | object-fit: cover;
180 | transition: opacity 0.3s ease;
181 | }
182 | .el-image:hover {
183 | opacity: 0.8;
184 | }
185 |
186 | .card-footer {
187 | display: flex;
188 | justify-content: center;
189 | align-items: center;
190 | overflow: hidden;
191 | text-overflow: ellipsis;
192 | white-space: nowrap;
193 | padding: 10px;
194 | background: rgba(0, 0, 0, 0.6);
195 | text-align: center;
196 | position: absolute;
197 | bottom: 0;
198 | left: 0;
199 | width: 100%;
200 | box-sizing: border-box;
201 | }
202 |
203 | .image-overlay {
204 | position: absolute;
205 | top: 0;
206 | left: 0;
207 | width: 100%;
208 | height: 100%;
209 | display: flex;
210 | align-items: center;
211 | justify-content: center;
212 | background: rgba(0, 0, 0, 0.6);
213 | opacity: 0;
214 | transition: opacity 0.3s ease;
215 | pointer-events: none;
216 | }
217 |
218 | .el-card, .el-card__body{
219 | border: none !important;
220 | }
221 | .el-card__body{
222 | padding: 14px !important;
223 | }
224 | .el-card:hover .image-overlay {
225 | opacity: 1;
226 | }
227 |
228 | .overlay-buttons {
229 | display: flex;
230 | gap: 10px;
231 | pointer-events: auto;
232 | }
233 |
234 | .pagination-container {
235 | display: flex;
236 | justify-content: center;
237 | margin-top: 16px;
238 | }
239 |
240 | .collect-icon {
241 | position: absolute;
242 | top: -1.3px;
243 | left: 10px;
244 | cursor: pointer;
245 | font-size: 1.5em;
246 | z-index: 10;
247 | transition: color 0.3s ease, transform 0.3s ease;
248 | }
249 | .collect-icon:hover {transform: scale(1.2);}
250 | .liked {color: #FFD7E4;}
251 | .not-liked {color: #b39edb80;}
252 |
253 | .footer {
254 | display: flex;
255 | justify-content: center;
256 | align-items: center;
257 | gap: 15px;
258 | margin-top: 20px;
259 | font-size: 0.9em;
260 | color: #555; /* 字体颜色改为黑色 */
261 | }
262 |
263 | .footer a {
264 | color: #555; /* 链接颜色 */
265 | text-decoration: none;
266 | transition: color 0.3s ease;
267 | }
268 |
269 | .footer a:hover {
270 | color: #333; /* 悬停时的链接颜色改为黑色 */
271 | }
272 |
273 | .footer i {
274 | color: #333; /* 图标颜色改为黑色 */
275 | }
276 |
277 | /* 适配移动端 */
278 | @media (max-width: 768px) {
279 | .content {
280 | grid-template-columns: 1fr; /* 单列布局 */
281 | gap: 10px;
282 | }
283 | .stats-text{display: none;}
284 | .header-content{padding: 8px 12px;}
285 | .stats{margin: 0 4px;}
286 | .stats, .actions i{margin: 0;}
287 | .el-card{aspect-ratio: unset; min-height: 180px;}
288 | .el-card__body{padding: 0;}
289 | .search-card {display: none;}
290 | .header-content .actions i{margin: 0 4px;}
291 | }
292 |
293 | /* 音视频卡片基础样式 */
294 | .video-card, .audio-card, .file-card {
295 | background: linear-gradient(135deg, #8a4bffd9 0%, #6d82ffd9 100%);
296 | border: none;
297 | border-radius: 16px !important;
298 | overflow: hidden;
299 | position: relative;
300 | justify-content: center;
301 | align-items: center;
302 | box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
303 | transition: transform 0.3s ease;
304 | }
305 |
306 | .video-card{
307 | background-color: #8EC5FC;
308 | background-image: linear-gradient(62deg, #8EC5FC 0%, #E0C3FC 100%);
309 | }
310 |
311 | .video-card .el-card__body{
312 | padding: 0 !important;
313 | }
314 |
315 | .audio-card.selected, .video-card.selected, .file-card.selected {
316 | background: linear-gradient(135deg, rgba(138, 75, 255, 0.85) 0%, rgba(255, 215, 228, 0.85) 100%);
317 | }
318 |
319 | .video-card:hover, .audio-card:hover, .file-card:hover {
320 | transform: scale(1.02);
321 | }
322 |
323 | .video-content, .audio-content, .file-content {
324 | padding: 12px;
325 | color: white;
326 | width: 100%;
327 | box-sizing: border-box;
328 | overflow: hidden;
329 | text-overflow: ellipsis;
330 | }
331 |
332 | .video-content{
333 | display: flex;
334 | flex-direction: column;
335 | justify-content: center;
336 | align-items: center;
337 | }
338 |
339 | .audio-header, .file-header {
340 | display: flex;
341 | align-items: center;
342 | margin-bottom: 15px;
343 | }
344 |
345 | .audio-avatar, .file-avatar {
346 | width: 48px;
347 | height: 48px;
348 | border-radius: 50%;
349 | background: rgba(255, 255, 255, 0.2);
350 | padding: 8px;
351 | margin-right: 15px;
352 | }
353 |
354 | .file-avatar{
355 | background: none;
356 | display: flex;
357 | justify-content: center;
358 | align-items: center;
359 | }
360 |
361 | .audio-avatar img {
362 | width: 100%;
363 | height: 100%;
364 | object-fit: contain;
365 | }
366 |
367 | .audio-info, .file-info {
368 | flex: 1;
369 | min-width: 0;
370 | }
371 |
372 | .video-title, .audio-title, .file-title {
373 | font-size: 16px;
374 | font-weight: 500;
375 | max-width: 100%;
376 | white-space: nowrap;
377 | overflow: hidden;
378 | text-overflow: ellipsis;
379 | margin-bottom: 4px;
380 | }
381 | .video-title{
382 | margin: 6px 0;
383 | font-size: 0.9em;
384 | }
385 |
386 | .audio-subtitle, .file-subtitle {
387 | font-size: 14px;
388 | color: rgba(255, 255, 255, 0.7);
389 | }
390 |
391 | /* 自定义audio元素样式 */
392 | .custom-audio-player {
393 | width: 100%;
394 | height: 42px;
395 | margin: 15px 0;
396 | border-radius: 28px;
397 | background: rgba(255, 255, 255, 0.2);
398 | }
399 |
400 | .video-controls, .audio-controls, .file-controls {
401 | display: flex;
402 | justify-content: center;
403 | gap: 12px;
404 | }
405 |
406 | .like-btn i, .select-btn i {
407 | font-size: 1.2em;
408 | }
409 |
410 | .like-btn .liked, .select-btn .selected {
411 | color: #FFD7E4;
412 | }
413 |
414 | .control-btn {
415 | width: 40px;
416 | height: 40px;
417 | flex-shrink: 0;
418 | border: none;
419 | border-radius: 50%;
420 | background: rgba(255, 255, 255, 0.2);
421 | color: white;
422 | cursor: pointer;
423 | display: flex;
424 | align-items: center;
425 | justify-content: center;
426 | transition: all 0.3s ease;
427 | flex-shrink: 0;
428 | z-index: 1; /* 确保按钮可点击 */
429 | }
430 |
431 | .control-btn:hover {
432 | background: rgba(255, 255, 255, 0.3);
433 | }
434 |
435 | /* 移动端适配 */
436 | @media (max-width: 768px) {
437 | .audio-card { max-height: none; }
438 | .custom-audio-player { height: 32px; }
439 | }
440 | .website-edit-dialog .el-textarea__inner{
441 | height: 240px !important;
442 | }
443 |
--------------------------------------------------------------------------------
/_nuxt/a84b71f5040faa8705cb.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[2],{316:function(t,n,r){for(var e,o=r(3),f=r(17),c=r(45),l=c("typed_array"),h=c("view"),v=!(!o.ArrayBuffer||!o.DataView),y=v,i=0,w="Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array".split(",");i<9;)(e=o[w[i++]])?(f(e.prototype,l,!0),f(e.prototype,h,!0)):y=!1;t.exports={ABV:v,CONSTR:y,TYPED:l,VIEW:h}},317:function(t,n,r){var e=r(43),o=r(27);t.exports=function(t){if(void 0===t)return 0;var n=e(t),r=o(n);if(n!==r)throw RangeError("Wrong length!");return r}},318:function(t,n,r){"use strict";var e=r(42),o=r(178),f=r(27);t.exports=function(t){for(var n=e(this),r=f(n.length),c=arguments.length,l=o(c>1?arguments[1]:void 0,r),h=c>2?arguments[2]:void 0,v=void 0===h?r:o(h,r);v>l;)n[l++]=t;return n}},325:function(t,n,r){r(326)("Uint8",1,(function(t){return function(data,n,r){return t(this,data,n,r)}}))},326:function(t,n,r){"use strict";if(r(7)){var e=r(44),o=r(3),f=r(12),c=r(8),l=r(316),h=r(327),v=r(46),y=r(179),w=r(47),d=r(17),A=r(180),E=r(43),_=r(27),S=r(317),I=r(178),B=r(83),L=r(21),x=r(58),W=r(11),F=r(42),T=r(184),U=r(120),m=r(181),P=r(56).f,V=r(185),N=r(45),O=r(2),R=r(328),D=r(122),M=r(85),Y=r(123),k=r(48),C=r(186),j=r(124),J=r(318),G=r(331),z=r(10),H=r(84),K=z.f,Q=H.f,X=o.RangeError,Z=o.TypeError,$=o.Uint8Array,tt=Array.prototype,nt=h.ArrayBuffer,et=h.DataView,it=R(0),ot=R(2),ut=R(3),ft=R(4),ct=R(5),at=R(6),st=D(!0),lt=D(!1),ht=Y.values,gt=Y.keys,vt=Y.entries,yt=tt.lastIndexOf,pt=tt.reduce,wt=tt.reduceRight,bt=tt.join,At=tt.sort,Et=tt.slice,_t=tt.toString,St=tt.toLocaleString,It=O("iterator"),Bt=O("toStringTag"),Lt=N("typed_constructor"),xt=N("def_constructor"),Wt=l.CONSTR,Ft=l.TYPED,Tt=l.VIEW,Ut=R(1,(function(t,n){return Ot(M(t,t[xt]),n)})),mt=f((function(){return 1===new $(new Uint16Array([1]).buffer)[0]})),Pt=!!$&&!!$.prototype.set&&f((function(){new $(1).set({})})),Vt=function(t,n){var r=E(t);if(r<0||r%n)throw X("Wrong offset!");return r},Nt=function(t){if(W(t)&&Ft in t)return t;throw Z(t+" is not a typed array!")},Ot=function(t,n){if(!(W(t)&&Lt in t))throw Z("It is not a typed array constructor!");return new t(n)},Rt=function(t,n){return Dt(M(t,t[xt]),n)},Dt=function(t,n){for(var r=0,e=n.length,o=Ot(t,e);e>r;)o[r]=n[r++];return o},Mt=function(t,n,r){K(t,n,{get:function(){return this._d[r]}})},Yt=function(source){var i,t,n,r,e,o,f=F(source),c=arguments.length,l=c>1?arguments[1]:void 0,h=void 0!==l,y=V(f);if(null!=y&&!T(y)){for(o=y.call(f),n=[],i=0;!(e=o.next()).done;i++)n.push(e.value);f=n}for(h&&c>2&&(l=v(l,arguments[2],2)),i=0,t=_(f.length),r=Ot(this,t);t>i;i++)r[i]=h?l(f[i],i):f[i];return r},kt=function(){for(var t=0,n=arguments.length,r=Ot(this,n);n>t;)r[t]=arguments[t++];return r},Ct=!!$&&f((function(){St.call(new $(1))})),jt=function(){return St.apply(Ct?Et.call(Nt(this)):Nt(this),arguments)},Jt={copyWithin:function(t,n){return G.call(Nt(this),t,n,arguments.length>2?arguments[2]:void 0)},every:function(t){return ft(Nt(this),t,arguments.length>1?arguments[1]:void 0)},fill:function(t){return J.apply(Nt(this),arguments)},filter:function(t){return Rt(this,ot(Nt(this),t,arguments.length>1?arguments[1]:void 0))},find:function(t){return ct(Nt(this),t,arguments.length>1?arguments[1]:void 0)},findIndex:function(t){return at(Nt(this),t,arguments.length>1?arguments[1]:void 0)},forEach:function(t){it(Nt(this),t,arguments.length>1?arguments[1]:void 0)},indexOf:function(t){return lt(Nt(this),t,arguments.length>1?arguments[1]:void 0)},includes:function(t){return st(Nt(this),t,arguments.length>1?arguments[1]:void 0)},join:function(t){return bt.apply(Nt(this),arguments)},lastIndexOf:function(t){return yt.apply(Nt(this),arguments)},map:function(t){return Ut(Nt(this),t,arguments.length>1?arguments[1]:void 0)},reduce:function(t){return pt.apply(Nt(this),arguments)},reduceRight:function(t){return wt.apply(Nt(this),arguments)},reverse:function(){for(var t,n=Nt(this).length,r=Math.floor(n/2),e=0;e1?arguments[1]:void 0)},sort:function(t){return At.call(Nt(this),t)},subarray:function(t,n){var r=Nt(this),e=r.length,o=I(t,e);return new(M(r,r[xt]))(r.buffer,r.byteOffset+o*r.BYTES_PER_ELEMENT,_((void 0===n?e:I(n,e))-o))}},Gt=function(t,n){return Rt(this,Et.call(Nt(this),t,n))},qt=function(t){Nt(this);var n=Vt(arguments[1],1),r=this.length,e=F(t),o=_(e.length),f=0;if(o+n>r)throw X("Wrong length!");for(;f255?255:255&e),data.v[A](r*n+data.o,e,mt)}(this,r,t)},enumerable:!0})};L?(E=r((function(t,data,r,e){y(t,E,v,"_d");var o,f,c,l,h=0,w=0;if(W(data)){if(!(data instanceof nt||"ArrayBuffer"==(l=x(data))||"SharedArrayBuffer"==l))return Ft in data?Dt(E,data):Yt.call(E,data);o=data,w=Vt(r,n);var A=data.byteLength;if(void 0===e){if(A%n)throw X("Wrong length!");if((f=A-w)<0)throw X("Wrong length!")}else if((f=_(e)*n)+w>A)throw X("Wrong length!");c=f/n}else c=S(data),o=new nt(f=c*n);for(d(t,"_d",{b:o,o:w,l:f,e:c,v:new et(o)});h>1,rt=23===n?V(2,-24)-V(2,-77):0,i=0,s=t<0||0===t&&1/t<0?1:0;for((t=P(t))!=t||t===U?(o=t!=t?1:0,e=h):(e=N(O(t)/R),t*(f=V(2,-e))<1&&(e--,f*=2),(t+=e+v>=1?rt/f:rt*V(2,1-v))*f>=2&&(e++,f/=2),e+v>=h?(o=0,e=h):e+v>=1?(o=(t*f-1)*V(2,n),e+=v):(o=t*V(2,v-1)*V(2,n),e=0));n>=8;c[i++]=255&o,o/=256,n-=8);for(e=e<0;c[i++]=255&e,e/=256,l-=8);return c[--i]|=128*s,c}function C(t,n,r){var e,o=8*r-n-1,f=(1<>1,l=o-7,i=r-1,s=t[i--],h=127&s;for(s>>=7;l>0;h=256*h+t[i],i--,l-=8);for(e=h&(1<<-l)-1,h>>=-l,l+=n;l>0;e=256*e+t[i],i--,l-=8);if(0===h)h=1-c;else{if(h===f)return e?NaN:s?-U:U;e+=V(2,n),h-=c}return(s?-1:1)*e*V(2,h-n)}function j(t){return t[3]<<24|t[2]<<16|t[1]<<8|t[0]}function J(t){return[255&t]}function G(t){return[255&t,t>>8&255]}function z(t){return[255&t,t>>8&255,t>>16&255,t>>24&255]}function H(t){return k(t,52,8)}function K(t){return k(t,23,4)}function Q(t,n,r){_(t[B],n,{get:function(){return this[r]}})}function X(view,t,n,r){var e=A(+n);if(e+t>view[M])throw T(L);var o=view[D]._b,f=e+view[Y],c=o.slice(f,f+t);return r?c:c.reverse()}function Z(view,t,n,r,e,o){var f=A(+n);if(f+t>view[M])throw T(L);for(var c=view[D]._b,l=f+view[Y],h=r(+e),i=0;iet;)($=nt[et++])in x||l(x,$,m[$]);f||(tt.constructor=x)}var view=new W(new x(2)),it=W[B].setInt8;view.setInt8(0,2147483648),view.setInt8(1,2147483649),!view.getInt8(0)&&view.getInt8(1)||h(W[B],{setInt8:function(t,n){it.call(this,t,n<<24>>24)},setUint8:function(t,n){it.call(this,t,n<<24>>24)}},!0)}else x=function(t){y(this,x,"ArrayBuffer");var n=A(t);this._b=S.call(new Array(n),0),this[M]=n},W=function(t,n,r){y(this,W,"DataView"),y(t,x,"DataView");var e=t[M],o=w(n);if(o<0||o>e)throw T("Wrong offset!");if(o+(r=void 0===r?e-o:d(r))>e)throw T("Wrong length!");this[D]=t,this[Y]=o,this[M]=r},o&&(Q(x,"byteLength","_l"),Q(W,"buffer","_b"),Q(W,"byteLength","_l"),Q(W,"byteOffset","_o")),h(W[B],{getInt8:function(t){return X(this,1,t)[0]<<24>>24},getUint8:function(t){return X(this,1,t)[0]},getInt16:function(t){var n=X(this,2,t,arguments[1]);return(n[1]<<8|n[0])<<16>>16},getUint16:function(t){var n=X(this,2,t,arguments[1]);return n[1]<<8|n[0]},getInt32:function(t){return j(X(this,4,t,arguments[1]))},getUint32:function(t){return j(X(this,4,t,arguments[1]))>>>0},getFloat32:function(t){return C(X(this,4,t,arguments[1]),23,4)},getFloat64:function(t){return C(X(this,8,t,arguments[1]),52,8)},setInt8:function(t,n){Z(this,1,t,J,n)},setUint8:function(t,n){Z(this,1,t,J,n)},setInt16:function(t,n){Z(this,2,t,G,n,arguments[2])},setUint16:function(t,n){Z(this,2,t,G,n,arguments[2])},setInt32:function(t,n){Z(this,4,t,z,n,arguments[2])},setUint32:function(t,n){Z(this,4,t,z,n,arguments[2])},setFloat32:function(t,n){Z(this,4,t,K,n,arguments[2])},setFloat64:function(t,n){Z(this,8,t,H,n,arguments[2])}});I(x,"ArrayBuffer"),I(W,"DataView"),l(W[B],c.VIEW,!0),n.ArrayBuffer=x,n.DataView=W},328:function(t,n,r){var e=r(46),o=r(121),f=r(42),c=r(27),l=r(329);t.exports=function(t,n){var r=1==t,h=2==t,v=3==t,y=4==t,w=6==t,d=5==t||w,A=n||l;return function(n,l,E){for(var _,S,I=f(n),B=o(I),L=e(l,E,3),x=c(B.length),W=0,F=r?A(n,x):h?A(n,0):void 0;x>W;W++)if((d||W in B)&&(S=L(_=B[W],W,I),t))if(r)F[W]=S;else if(S)switch(t){case 3:return!0;case 5:return _;case 6:return W;case 2:F.push(_)}else if(y)return!1;return w?-1:v||y?y:F}}},329:function(t,n,r){var e=r(330);t.exports=function(t,n){return new(e(t))(n)}},330:function(t,n,r){var e=r(11),o=r(182),f=r(2)("species");t.exports=function(t){var n;return o(t)&&("function"!=typeof(n=t.constructor)||n!==Array&&!o(n.prototype)||(n=void 0),e(n)&&null===(n=n[f])&&(n=void 0)),void 0===n?Array:n}},331:function(t,n,r){"use strict";var e=r(42),o=r(178),f=r(27);t.exports=[].copyWithin||function(t,n){var r=e(this),c=f(r.length),l=o(t,c),h=o(n,c),v=arguments.length>2?arguments[2]:void 0,y=Math.min((void 0===v?c:o(v,c))-h,c-l),w=1;for(h0;)h in r?r[l]=r[h]:delete r[l],l+=w,h+=w;return r}}}]);
--------------------------------------------------------------------------------
/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
50 |
51 |
52 |
53 |
54 | 记录总数量:
55 | {{ Number }}
56 |
57 |
58 |
74 |
75 |
76 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | {{ scope.row.metadata }}
94 |
95 | {{ scope.row.metadata }}
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | 复制地址
106 | 白名单
107 | 黑名单
108 | 删除
109 |
110 |
111 |
112 | 加载更多
113 |
114 |
115 |
116 |
117 |
118 |
119 |
121 |
122 |
124 |
340 |
350 |
357 |
358 |
--------------------------------------------------------------------------------
/_nuxt/b46e75617207ae5013d0.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[4],{311:function(t,e,o){var content=o(320);"string"==typeof content&&(content=[[t.i,content,""]]),content.locals&&(t.exports=content.locals);(0,o(41).default)("9e96ac5e",content,!0,{sourceMap:!1})},312:function(t,e,o){var content=o(322);"string"==typeof content&&(content=[[t.i,content,""]]),content.locals&&(t.exports=content.locals);(0,o(41).default)("3c22903d",content,!0,{sourceMap:!1})},313:function(t,e,o){var content=o(324);"string"==typeof content&&(content=[[t.i,content,""]]),content.locals&&(t.exports=content.locals);(0,o(41).default)("483543ae",content,!0,{sourceMap:!1})},314:function(t,e,o){var content=o(333);"string"==typeof content&&(content=[[t.i,content,""]]),content.locals&&(t.exports=content.locals);(0,o(41).default)("5d65cc87",content,!0,{sourceMap:!1})},315:function(t,e,o){var content=o(335);"string"==typeof content&&(content=[[t.i,content,""]]),content.locals&&(t.exports=content.locals);(0,o(41).default)("15da84d3",content,!0,{sourceMap:!1})},319:function(t,e,o){"use strict";var n=o(311);o.n(n).a},320:function(t,e,o){(e=o(40)(!1)).push([t.i,".background-container[data-v-045ae8ab]{background-color:linear-gradient(240deg,rgba(150,50,50,.3),rgba(0,0,200,0));z-index:-1}#background-slider figure[data-v-045ae8ab],.background-container[data-v-045ae8ab]{position:absolute;width:100%;height:100%;top:0;left:0;background-size:cover;background-position:50%;background-repeat:no-repeat;margin:0}#background-slider figure[data-v-045ae8ab]{color:transparent;opacity:0;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-animation:imageAnimation-data-v-045ae8ab 30s linear -.5s infinite;animation:imageAnimation-data-v-045ae8ab 30s linear -.5s infinite}@-webkit-keyframes imageAnimation-data-v-045ae8ab{0%{opacity:0;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}3%{opacity:1;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}20%{opacity:1}28%{opacity:0}to{opacity:0}}",""]),t.exports=e},321:function(t,e,o){"use strict";var n=o(312);o.n(n).a},322:function(t,e,o){(e=o(40)(!1)).push([t.i,".header[data-v-c757ee00]{color:#fff;display:-webkit-box;display:flex;-webkit-box-pack:end;justify-content:flex-end}.header .icon[data-v-c757ee00]{cursor:pointer;width:28px;height:28px;fill:#fff}.header .icon[data-v-c757ee00]:hover{opacity:.7}",""]),t.exports=e},323:function(t,e,o){"use strict";var n=o(313);o.n(n).a},324:function(t,e,o){(e=o(40)(!1)).push([t.i,".footer[data-v-5d5649c4]{font-size:12px;color:#fff}.footer a[data-v-5d5649c4]{color:#fff;text-decoration:none;font-weight:700}.footer a[data-v-5d5649c4]:hover{opacity:.7}",""]),t.exports=e},332:function(t,e,o){"use strict";var n=o(314);o.n(n).a},333:function(t,e,o){(e=o(40)(!1)).push([t.i,'[data-v-793b8fc8]::-webkit-scrollbar{display:none}[data-tooltip][data-v-793b8fc8]{position:relative}[data-tooltip][data-v-793b8fc8]:after,[data-tooltip][data-v-793b8fc8]:before{text-transform:none;font-size:1.3rem;font-family:Helvetica,sans-serif,微软雅黑;line-height:1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none;position:absolute;display:none;left:50%;-webkit-transform:translate(-50%,.5rem);transform:translate(-50%,.5rem)}[data-tooltip][data-v-793b8fc8]:before{content:" ";top:100%;border-color:transparent transparent #333;border-style:solid;border-width:0 1rem 1rem}[data-tooltip][data-v-793b8fc8]:after{content:attr(data-tooltip);text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:.6rem 1rem;border-radius:.3rem;box-shadow:0 1em 2em -.5em rgba(0,0,0,.35);background:#333;color:#fff;z-index:1000;top:calc(100% + 5px)}[data-tooltip][data-v-793b8fc8]:hover:after,[data-tooltip][data-v-793b8fc8]:hover:before{display:block}[data-tooltip][data-v-793b8fc8]:after,[data-tooltip][data-v-793b8fc8]:before{display:none!important}.flex[data-v-793b8fc8]{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center}.upload-main[data-v-793b8fc8]{width:314px;height:370px}.upload-main[data-v-793b8fc8],.wrapper[data-v-793b8fc8]{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center}.wrapper[data-v-793b8fc8]{height:100%;max-width:314px;height:370px;background:#fff url(/bg.svg);background-size:110%;background-repeat:no-repeat;background-position:top;border-radius:3px;box-shadow:0 0 32px 0 rgba(12,12,13,.1),0 2px 16px 0 rgba(12,12,13,.05);color:#5e6878;font-size:14px}.area[data-v-793b8fc8],.wrapper[data-v-793b8fc8]{width:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column}.area[data-v-793b8fc8]{height:100%;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center}.svg-wrapper[data-v-793b8fc8]{width:80px;height:80px;border-radius:50%;position:relative;border:4px solid #c7cfd7}.svg-wrapper.dragover[data-v-793b8fc8]{border-color:#0297f8}.svg-wrapper[data-v-793b8fc8]:before{content:" ";position:absolute;width:calc(100% + 2px);height:calc(100% + 2px);top:-1px;left:-1px;border-radius:50%}.svg-wrapper .svg-box[data-v-793b8fc8]{position:absolute;width:60px;height:60px;padding:10px;overflow:hidden;border-radius:50%}.svg-wrapper .svg-box svg.upload-icon[data-v-793b8fc8]{width:100%;height:100%}.waitting .svg-wrapper[data-v-793b8fc8]:before{-webkit-animation:bo-data-v-793b8fc8 1.5s linear infinite;animation:bo-data-v-793b8fc8 1.5s linear infinite}.text-area[data-v-793b8fc8]{padding:50px 0 10px;font-size:12px}.upload-btn-area input[name=Files][data-v-793b8fc8]{display:none}.upload-btn-area .btn-upload[data-v-793b8fc8]{background-color:#0297f8;border-radius:40px;display:inline-block;color:#fff;font-weight:700;padding:8px 30px;cursor:pointer}.upload-btn-area .btn-upload[data-v-793b8fc8]:hover{opacity:.8;background-color:rgba(2,151,248,.85)}.url-box[data-v-793b8fc8]{height:43px;width:80%;margin-top:15px}.copy-url[data-v-793b8fc8]{padding-left:20px;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center}.copy-url .input-group[data-v-793b8fc8]{display:-webkit-box;display:flex;background-repeat:no-repeat;border:1px solid #d1d5da;border-radius:3px}.copy-url .input-group[data-v-793b8fc8],.copy-url .input-group .input-sm[data-v-793b8fc8]{-webkit-box-flex:1;flex:1;box-shadow:inset 0 1px 2px rgba(27,31,35,.075)}.copy-url .input-group .input-sm[data-v-793b8fc8]{outline:none;font-size:12px;line-height:20px;padding:3px 5px;border:none}.copy-url .input-group .input-group-button[data-v-793b8fc8]{padding:0 8px;background-color:#eff3f6;background-image:-webkit-gradient(linear,left top,left bottom,from(#fafbfc),color-stop(90%,#eff3f6));background-image:linear-gradient(-180deg,#fafbfc,#eff3f6 90%);color:#24292e;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;cursor:pointer;border-left:1px solid #d1d5da}.copy-url .input-group .input-group-button[data-v-793b8fc8]:hover{background-color:#e6ebf1;background-image:-webkit-gradient(linear,left top,left bottom,from(#f0f3f6),color-stop(90%,#e6ebf1));background-image:linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%);background-position:-.5em;border-color:rgba(27,31,35,.35)}.copy-url .input-group .input-group-button[data-v-793b8fc8]:active{background-color:#e9ecef;background-image:none;border-color:rgba(27,31,35,.35);box-shadow:inset 0 .15em .3em rgba(27,31,35,.15)}.copy-url .re-upload[data-v-793b8fc8]{cursor:pointer;padding:0 5px;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center}.uploading svg.upload-icon[data-v-793b8fc8]{-webkit-animation:up-data-v-793b8fc8 1s linear infinite;animation:up-data-v-793b8fc8 1s linear infinite}.head[data-v-793b8fc8]{width:100%;padding:15px 20px;font-weight:bolder}.head .head-title[data-v-793b8fc8]{-webkit-box-flex:1;flex:1}.head .head-download[data-v-793b8fc8]{padding:0 20px;color:#0297f8;font-size:12px;cursor:pointer}.head .head-op[data-v-793b8fc8]{font-size:12px;color:red;font-weight:500;cursor:pointer}.pics[data-v-793b8fc8]{-webkit-box-flex:1;flex:1;width:calc(100% - 40px);overflow:hidden;overflow-y:auto}@-webkit-keyframes up-data-v-793b8fc8{0%{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@keyframes up-data-v-793b8fc8{0%{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@-webkit-keyframes bo-data-v-793b8fc8{0%{-webkit-transform:scale(1);transform:scale(1);border:1px solid #c7cfd7}to{-webkit-transform:scale(1.5);transform:scale(1.5);border:1px solid rgba(199,207,215,.1)}}@keyframes bo-data-v-793b8fc8{0%{-webkit-transform:scale(1);transform:scale(1);border:1px solid #c7cfd7}to{-webkit-transform:scale(1.5);transform:scale(1.5);border:1px solid rgba(199,207,215,.1)}}.alert-text[data-v-793b8fc8]{color:#1bc1a1;font-size:12px}',""]),t.exports=e},334:function(t,e,o){"use strict";var n=o(315);o.n(n).a},335:function(t,e,o){(e=o(40)(!1)).push([t.i,'@font-face{font-family:阿里妈妈数黑体 Bold;font-weight:700;src:url(//at.alicdn.com/wf/webfont/vyMYqE6AQ53l/QuXl5poIEmsBTN1RFuJ49.woff2) format("woff2"),url(//at.alicdn.com/wf/webfont/vyMYqE6AQ53l/TgFpb2VvlZLFg0EQ_RgjM.woff) format("woff");font-display:swap}.container[data-v-5e6831cc]{margin:0 auto;min-height:100vh;flex-direction:column;padding:30px;background:linear-gradient(240deg,rgba(150,50,50,.3),rgba(0,0,200,0))}.container[data-v-5e6831cc],.main[data-v-5e6831cc]{display:-webkit-box;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal}.main[data-v-5e6831cc]{-webkit-box-flex:1;flex:1;flex-direction:column;padding:30px 0;-webkit-box-align:center;align-items:center}.main .title[data-v-5e6831cc]{font-family:阿里妈妈数黑体 Bold;color:#fff;font-size:24px;font-weight:bolder;padding:30px 0 10px}',""]),t.exports=e},336:function(t,e,o){"use strict";o.r(e);var n=o(53),r=o.n(n),c={data:function(){return{bgJson:[]}},mounted:function(){this.getBingHpImage()},methods:{getBingHpImage:function(){var t=this;r.a.post(location.origin+"/api/bing/wallpaper",{n:5}).then((function(e){e.data.data.map((function(e,o){t.bgJson.push({imgUrl:"https://cn.bing.com"+e.url,delay:6*o})}))}))}}},l=(o(319),o(28)),d=Object(l.a)(c,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"background-container"},[e("div",{attrs:{id:"background-slider"}},this._l(this.bgJson,(function(t,o){return e("figure",{key:o,style:{backgroundImage:"url("+t.imgUrl+")",animationDelay:t.delay+"s"}})})),0)])}),[],!1,null,"045ae8ab",null).exports,f=(o(321),Object(l.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"header"},[e("svg",{attrs:{width:"22",height:"22",viewBox:"0 0 48 48",fill:"none",xmlns:"http://www.w3.org/2000/svg"}},[e("circle",{attrs:{cx:"24",cy:"24",r:"20",stroke:"#fff","stroke-width":"4","stroke-linecap":"butt","stroke-linejoin":"miter"}}),this._v(" "),e("path",{attrs:{d:"M9 37L17 28L33 41",stroke:"#fff","stroke-width":"4","stroke-linecap":"butt","stroke-linejoin":"miter"}}),this._v(" "),e("circle",{attrs:{cx:"18",cy:"17",r:"4",fill:"none",stroke:"#fff","stroke-width":"4"}}),this._v(" "),e("path",{attrs:{d:"M24 33L32 23L42 31",stroke:"#fff","stroke-width":"4","stroke-linecap":"butt","stroke-linejoin":"miter"}})])])}),[],!1,null,"c757ee00",null).exports),v=(o(323),Object(l.a)({},(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"footer"},[this._v("\n 基于 "),e("a",{attrs:{href:"https://telegra.ph",target:"_blank"}},[this._v("Telegraph")]),this._v(" 的图片上传工具\n")])}],!1,null,"5d5649c4",null).exports),h=(o(325),o(183),o(187),o(78)),m={data:function(){return{status:"waitting",imgUrl:"",defcloud:"",markdown:!1,uptoken:"",config:"",file:{},copyBtn:null,isCopy:!1}},computed:Object(h.a)({markdownUrl:function(){return"")},showText:function(){return this.markdown?this.markdownUrl:this.imgUrl}},"showText",{get:function(){return this.markdown?this.markdownUrl:this.imgUrl},set:function(t){this.markdown=t}}),mounted:function(){var t=this;this.pasteUpload(),this.copyBtn=new this.clipboard(this.$refs.copy),this.copyBtn.on("success",(function(e){t.isCopy=!0,setTimeout((function(){t.isCopy=!1}),1500)}))},methods:{pasteUpload:function(){var t=this;document.addEventListener("paste",(function(e){if(e.clipboardData.items[0].type.indexOf("image")>-1){t.status="uploading";var o=new FileReader,n=e.clipboardData.items[0].getAsFile();o.onload=function(e){t.upload(t.dataURLtoFile(this.result))},o.readAsDataURL(n)}}))},dataURLtoFile:function(t){for(var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"tmp.png",o=t.split(","),n=o[0].match(/:(.*?);/)[1],r=atob(o[1]),c=r.length,l=new Uint8Array(c);c--;)l[c]=r.charCodeAt(c);return new File([l],e,{type:n})},uploadInputchange:function(){var t=document.getElementById("upFiles").files[0];this.status="uploading",this.upload(t)},clearFilelist:function(){this.status="waitting",this.fileList={},document.getElementById("upFiles").value=""},focus:function(){this.$refs.copyTxt.select()},upload:function(t){var e=this,o=new FormData;o.append("file",t),r.a.post("/upload",o).then((function(t){200===t.status?(e.status="done",e.imgUrl=location.origin+t.data[0].src):e.showError()})).catch((function(){e.showError()}))},clear:function(){this.file={},document.getElementById("upFiles").value="",this.status="waitting"},showError:function(){var t=this;this.status="error",setTimeout((function(){t.clear()}),2e3)}}},w=(o(332),{head:{title:"Telegraph-Image|免费图床"},components:{Background:d,Header:f,Footer:v,Upload:Object(l.a)(m,(function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("div",{staticClass:"upload-main",attrs:{id:"paste"}},[o("div",{staticClass:"wrapper",class:t.status},[o("div",{directives:[{name:"show",rawName:"v-show",value:"waitting"==t.status,expression:"status == 'waitting'"}],staticClass:"area waitting"},[o("div",{staticClass:"svg-wrapper flex"},[o("div",{staticClass:"svg-box"},[o("svg",{staticClass:"upload-icon",attrs:{viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"}},[o("path",{attrs:{d:"M422.4 704l-94.72-143.36c-15.36-23.04-46.08-30.72-71.68-15.36l-15.36 15.36-130.56 204.8c-12.8 25.6-7.68 56.32 17.92 71.68 7.68 5.12 17.92 7.68 25.6 7.68h256c28.16 0 51.2-23.04 51.2-51.2 0-7.68-2.56-15.36-5.12-23.04l-33.28-66.56z",fill:"#A5C8F4"}}),t._v(" "),o("path",{attrs:{d:"M307.2 358.4c-43.52 0-76.8-33.28-76.8-76.8s33.28-76.8 76.8-76.8 76.8 33.28 76.8 76.8-33.28 76.8-76.8 76.8z m327.68-33.28c5.12-7.68 12.8-15.36 20.48-17.92 25.6-12.8 56.32 0 69.12 23.04L944.64 793.6c2.56 7.68 5.12 15.36 5.12 23.04 0 28.16-23.04 51.2-51.2 51.2H378.88c-10.24 0-20.48-2.56-30.72-10.24-23.04-15.36-28.16-48.64-12.8-71.68l56.32-79.36 243.2-381.44z",fill:"#2589FF"}})])])]),t._v(" "),t._m(0),t._v(" "),o("div",{staticClass:"upload-btn-area"},[o("input",{attrs:{accept:"image/jpeg, image/png, image/gif, video/mp4",id:"upFiles",name:"Files",type:"file"},on:{change:t.uploadInputchange}}),t._v(" "),o("labeL",{staticClass:"btn-upload",attrs:{for:"upFiles"}},[t._v("选择上传图片或视频")])],1)]),t._v(" "),o("div",{directives:[{name:"show",rawName:"v-show",value:"uploading"==t.status,expression:"status == 'uploading'"}],staticClass:"area uploading"},[o("div",{staticClass:"svg-wrapper flex"},[o("div",{staticClass:"svg-box"},[o("svg",{staticClass:"upload-icon",attrs:{viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"}},[o("path",{attrs:{d:"M554.666667 268.8v601.6h-85.333334V268.8L337.066667 401.066667 277.333333 341.333333 512 106.666667 746.666667 341.333333l-59.733334 59.733334L554.666667 268.8z",fill:"#0075ff"}})])])]),t._v(" "),t._m(1)]),t._v(" "),o("div",{directives:[{name:"show",rawName:"v-show",value:"done"==t.status,expression:"status == 'done'"}],staticClass:"area done"},[o("div",{staticClass:"svg-wrapper flex"},[o("div",{staticClass:"svg-box"},[o("svg",{staticClass:"upload-icon",attrs:{viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"}},[o("path",{attrs:{d:"M392.533333 806.4L85.333333 503.466667l59.733334-59.733334 247.466666 247.466667L866.133333 213.333333l59.733334 59.733334L392.533333 806.4z",fill:"#0075ff"}})])])]),t._v(" "),o("div",{staticClass:"text-area"},[t.isCopy?o("span",{staticClass:"alert-text"},[t._v("已成功复制图片地址!")]):o("span",[t._v("复制下面的图片地址 或者 取消重新上传")])]),t._v(" "),o("div",{staticClass:"url-box"},[o("div",{directives:[{name:"show",rawName:"v-show",value:t.imgUrl,expression:"imgUrl"}],staticClass:"copy-url"},[o("div",{staticClass:"input-group"},[o("input",{directives:[{name:"model",rawName:"v-model",value:t.showText,expression:"showText"}],ref:"copyTxt",staticClass:"input-sm",attrs:{readonly:"",type:"text",id:"url-content"},domProps:{value:t.showText},on:{focus:t.focus,input:function(e){e.target.composing||(t.showText=e.target.value)}}}),t._v(" "),o("div",{ref:"copy",staticClass:"input-group-button",attrs:{"data-clipboard-target":"#url-content"}},[o("svg",{staticClass:"octicon octicon-clippy",attrs:{"aria-hidden":"true",height:"16",version:"1.1",viewBox:"0 0 14 16",width:"14"}},[o("path",{attrs:{d:"M2 13h4v1H2v-1zm5-6H2v1h5V7zm2 3V8l-3 3 3 3v-2h5v-2H9zM4.5 9H2v1h2.5V9zM2 12h2.5v-1H2v1zm9 1h1v2c-.02.28-.11.52-.3.7-.19.18-.42.28-.7.3H1c-.55 0-1-.45-1-1V4c0-.55.45-1 1-1h3c0-1.11.89-2 2-2 1.11 0 2 .89 2 2h3c.55 0 1 .45 1 1v5h-1V6H1v9h10v-2zM2 5h8c0-.55-.45-1-1-1H8c-.55 0-1-.45-1-1s-.45-1-1-1-1 .45-1 1-.45 1-1 1H3c-.55 0-1 .45-1 1z","fill-rule":"evenodd"}})])])]),t._v(" "),o("div",{staticClass:"re-upload",on:{click:t.clear}},[o("svg",{attrs:{height:"26",viewBox:"0 0 1024 1024",width:"26",xmlns:"http://www.w3.org/2000/svg"}},[o("path",{attrs:{d:"M396.8 200.533333l64 64L384 341.333333h298.666667c119.466667 0 213.333333 93.866667 213.333333 213.333334s-93.866667 213.333333-213.333333 213.333333H298.666667v-85.333333h384c72.533333 0 128-55.466667 128-128s-55.466667-128-128-128H170.666667l226.133333-226.133334z",fill:"#d73a49","p-id":"7650"}})])])])])]),t._v(" "),o("div",{directives:[{name:"show",rawName:"v-show",value:"error"==t.status,expression:"status == 'error'"}],staticClass:"area error"},[o("div",{staticClass:"svg-wrapper flex"},[o("div",{staticClass:"svg-box"},[o("svg",{staticClass:"upload-icon",attrs:{viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"}},[o("path",{attrs:{d:"M809.222867 150.531412 868.688213 210.004945 568.397986 510.292102 868.688213 810.587446 809.222867 870.055862 508.93264 569.771775 208.644459 870.055862 149.169903 810.587446 449.461153 510.292102 149.169903 210.004945 208.644459 150.531412 508.93264 450.823686Z",fill:"#d81e06"}})])])]),t._v(" "),t._m(2)])])])}),[function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"text-area"},[e("span",[this._v("也可直接截图并粘贴到这里")])])},function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"text-area"},[e("span",[this._v("正在上传,请稍等…")])])},function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"text-area"},[e("span",[this._v("出错啦,请重新上传")])])}],!1,null,"793b8fc8",null).exports}}),x=(o(334),Object(l.a)(w,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"container"},[e("Background"),this._v(" "),e("Header"),this._v(" "),e("div",{staticClass:"main"},[e("div",{staticClass:"title"},[this._v("Telegraph-Image")]),this._v(" "),e("Upload")],1),this._v(" "),e("Footer")],1)}),[],!1,null,"5e6831cc",null));e.default=x.exports}}]);
2 |
--------------------------------------------------------------------------------
/_nuxt/fbd198cfd0f4459e2725.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{1:function(t,e,n){"use strict";n.d(e,"i",(function(){return m})),n.d(e,"j",(function(){return x})),n.d(e,"a",(function(){return v})),n.d(e,"o",(function(){return y})),n.d(e,"e",(function(){return w})),n.d(e,"f",(function(){return _})),n.d(e,"c",(function(){return k})),n.d(e,"n",(function(){return C})),n.d(e,"h",(function(){return O})),n.d(e,"p",(function(){return j})),n.d(e,"k",(function(){return R})),n.d(e,"m",(function(){return P})),n.d(e,"d",(function(){return T})),n.d(e,"b",(function(){return S})),n.d(e,"g",(function(){return N})),n.d(e,"l",(function(){return A}));n(140),n(49);var r=n(54),o=(n(187),n(211),n(212),n(38)),c=(n(141),n(142),n(215),n(218),n(143),n(63),n(5)),f=(n(86),n(33),n(19),n(94),n(95),n(78)),l=n(0);function h(object,t){var e=Object.keys(object);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(object);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(object,t).enumerable}))),e.push.apply(e,n)}return e}function d(t){for(var i=1;i1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"components";return Array.prototype.concat.apply([],t.matched.map((function(t,r){return Object.keys(t[n]).map((function(o){return e&&e.push(r),t[n][o]}))})))}function _(t){return w(t,arguments.length>1&&void 0!==arguments[1]&&arguments[1],"instances")}function k(t,e){return Array.prototype.concat.apply([],t.matched.map((function(t,n){return Object.keys(t.components).reduce((function(r,o){return t.components[o]?r.push(e(t.components[o],t.instances[o],t,o,n)):delete t.components[o],r}),[])})))}function C(t,e){return Promise.all(k(t,function(){var t=Object(c.a)(regeneratorRuntime.mark((function t(n,r,o,c){return regeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if("function"!=typeof n||n.options){t.next=4;break}return t.next=3,n();case 3:n=t.sent;case 4:return o.components[c]=n=y(n),t.abrupt("return","function"==typeof e?e(n,r,o,c):n);case 6:case"end":return t.stop()}}),t)})));return function(e,n,r,o){return t.apply(this,arguments)}}()))}function O(t){return $.apply(this,arguments)}function $(){return($=Object(c.a)(regeneratorRuntime.mark((function t(e){return regeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(e){t.next=2;break}return t.abrupt("return");case 2:return t.next=4,C(e);case 4:return t.abrupt("return",d({},e,{meta:w(e).map((function(t,n){return d({},t.options.meta,{},(e.matched[n]||{}).meta)}))}));case 5:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function j(t,e){return E.apply(this,arguments)}function E(){return(E=Object(c.a)(regeneratorRuntime.mark((function t(e,n){var c,f,l,h;return regeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return e.context||(e.context={isStatic:!0,isDev:!1,isHMR:!1,app:e,payload:n.payload,error:n.error,base:"/",env:{}},n.req&&(e.context.req=n.req),n.res&&(e.context.res=n.res),n.ssrContext&&(e.context.ssrContext=n.ssrContext),e.context.redirect=function(t,path,n){if(t){e.context._redirected=!0;var r=Object(o.a)(path);if("number"==typeof t||"undefined"!==r&&"object"!==r||(n=path||{},path=t,r=Object(o.a)(path),t=302),"object"===r&&(path=e.router.resolve(path).route.fullPath),!/(^[.]{1,2}\/)|(^\/(?!\/))/.test(path))throw path=z(path,n),window.location.replace(path),new Error("ERR_REDIRECT");e.context.next({path:path,query:n,status:t})}},e.context.nuxtState=window.__NUXT__),t.next=3,Promise.all([O(n.route),O(n.from)]);case 3:c=t.sent,f=Object(r.a)(c,2),l=f[0],h=f[1],n.route&&(e.context.route=l),n.from&&(e.context.from=h),e.context.next=n.next,e.context._redirected=!1,e.context._errored=!1,e.context.isHMR=!1,e.context.params=e.context.route.params||{},e.context.query=e.context.route.query||{};case 15:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function R(t,e){return!t.length||e._redirected||e._errored?Promise.resolve():P(t[0],e).then((function(){return R(t.slice(1),e)}))}function P(t,e){var n;return(n=2===t.length?new Promise((function(n){t(e,(function(t,data){t&&e.error(t),n(data=data||{})}))})):t(e))&&n instanceof Promise&&"function"==typeof n.then?n:Promise.resolve(n)}function T(base,t){var path=decodeURI(window.location.pathname);return"hash"===t?window.location.hash.replace(/^#\//,""):(base&&0===path.indexOf(base)&&(path=path.slice(base.length)),(path||"/")+window.location.search+window.location.hash)}function S(t,e){return function(t,e){for(var n=new Array(t.length),i=0;i1&&void 0!==arguments[1]?arguments[1]:y,n=arguments.length>2?arguments[2]:void 0;return w.call(this,t,e,n)},c.default.use(x.a);var _={mode:"history",base:decodeURI("/"),linkActiveClass:"nuxt-link-active",linkExactActiveClass:"nuxt-link-exact-active",scrollBehavior:function(t,e,n){var r=!1,o=Object(v.e)(t);o.length<2&&o.every((function(t){return!1!==t.options.scrollToTop}))?r={x:0,y:0}:o.some((function(t){return t.options.scrollToTop}))&&(r={x:0,y:0}),n&&(r=n);var c=window.$nuxt;return t.path===e.path&&t.hash!==e.hash&&c.$nextTick((function(){return c.$emit("triggerScroll")})),new Promise((function(e){c.$once("triggerScroll",(function(){if(t.hash){var n=t.hash;void 0!==window.CSS&&void 0!==window.CSS.escape&&(n="#"+window.CSS.escape(n.substr(1)));try{document.querySelector(n)&&(r={selector:n})}catch(t){console.warn("Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).")}}e(r)}))}))},routes:[{path:"/",component:function(){return Object(v.j)(Promise.all([n.e(2),n.e(4)]).then(n.bind(null,336)))},name:"index"},{path:"/*",component:function(){return Object(v.j)(n.e(3).then(n.bind(null,337)))},name:"all"}],fallback:!1};for(var k,C={name:"NuxtChild",functional:!0,props:{nuxtChildKey:{type:String,default:""},keepAlive:Boolean,keepAliveProps:{type:Object,default:void 0}},render:function(t,e){var n=e.parent,data=e.data,r=e.props;data.nuxtChild=!0;for(var o=n,c=n.$nuxt.nuxt.transitions,f=n.$nuxt.nuxt.defaultTransition,l=0;n;)n.$vnode&&n.$vnode.data.nuxtChild&&l++,n=n.$parent;data.nuxtChildDepth=l;var h=c[l]||f,d={};O.forEach((function(t){void 0!==h[t]&&(d[t]=h[t])}));var m={};$.forEach((function(t){"function"==typeof h[t]&&(m[t]=h[t].bind(o))}));var x=m.beforeEnter;if(m.beforeEnter=function(t){if(window.$nuxt.$nextTick((function(){window.$nuxt.$emit("triggerScroll")})),x)return x.call(o,t)},!1===h.css){var v=m.leave;(!v||v.length<2)&&(m.leave=function(t,e){v&&v.call(o,t),o.$nextTick(e)})}var y=t("routerView",data);return r.keepAlive&&(y=t("keep-alive",{props:r.keepAliveProps},[y])),t("transition",{props:d,on:m},[y])}},O=["name","mode","appear","css","type","duration","enterClass","leaveClass","appearClass","enterActiveClass","enterActiveClass","leaveActiveClass","appearActiveClass","enterToClass","leaveToClass","appearToClass"],$=["beforeEnter","enter","afterEnter","enterCancelled","beforeLeave","leave","afterLeave","leaveCancelled","beforeAppear","appear","afterAppear","appearCancelled"],j={name:"NuxtError",props:{error:{type:Object,default:null}},computed:{statusCode:function(){return this.error&&this.error.statusCode||500},message:function(){return this.error.message||"Error"}},head:function(){return{title:this.message,meta:[{name:"viewport",content:"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"}]}}},E=(n(222),n(28)),R=Object(E.a)(j,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"__nuxt-error-page"},[n("div",{staticClass:"error"},[n("svg",{attrs:{xmlns:"http://www.w3.org/2000/svg",width:"90",height:"90",fill:"#DBE1EC",viewBox:"0 0 48 48"}},[n("path",{attrs:{d:"M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z"}})]),t._v(" "),n("div",{staticClass:"title"},[t._v(t._s(t.message))]),t._v(" "),404===t.statusCode?n("p",{staticClass:"description"},[n("NuxtLink",{staticClass:"error-link",attrs:{to:"/"}},[t._v("Back to the home page")])],1):t._e(),t._v(" "),t._m(0)])])}),[function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"logo"},[e("a",{attrs:{href:"https://nuxtjs.org",target:"_blank",rel:"noopener"}},[this._v("Nuxt.js")])])}],!1,null,null,null).exports,P=(n(141),n(142),n(143),n(54)),T={name:"Nuxt",components:{NuxtChild:C,NuxtError:R},props:{nuxtChildKey:{type:String,default:void 0},keepAlive:Boolean,keepAliveProps:{type:Object,default:void 0},name:{type:String,default:"default"}},errorCaptured:function(t){this.displayingNuxtError&&(this.errorFromNuxtError=t,this.$forceUpdate())},computed:{routerViewKey:function(){if(void 0!==this.nuxtChildKey||this.$route.matched.length>1)return this.nuxtChildKey||Object(v.b)(this.$route.matched[0].path)(this.$route.params);var t=Object(P.a)(this.$route.matched,1)[0];if(!t)return this.$route.path;var e=t.components.default;if(e&&e.options){var n=e.options;if(n.key)return"function"==typeof n.key?n.key(this.$route):n.key}return/\/$/.test(t.path)?this.$route.path:this.$route.path.replace(/\/$/,"")}},beforeCreate:function(){c.default.util.defineReactive(this,"nuxt",this.$root.$options.nuxt)},render:function(t){var e=this;return this.nuxt.err?this.errorFromNuxtError?(this.$nextTick((function(){return e.errorFromNuxtError=!1})),t("div",{},[t("h2","An error occured while showing the error page"),t("p","Unfortunately an error occured and while showing the error page another error occured"),t("p","Error details: ".concat(this.errorFromNuxtError.toString())),t("nuxt-link",{props:{to:"/"}},"Go back to home")])):(this.displayingNuxtError=!0,this.$nextTick((function(){return e.displayingNuxtError=!1})),t(R,{props:{error:this.nuxt.err}})):t("NuxtChild",{key:this.routerViewKey,props:this.$props})}},S=(n(86),{name:"NuxtLoading",data:function(){return{percent:0,show:!1,canSucceed:!0,reversed:!1,skipTimerCount:0,rtl:!1,throttle:200,duration:5e3,continuous:!1}},computed:{left:function(){return!(!this.continuous&&!this.rtl)&&(this.rtl?this.reversed?"0px":"auto":this.reversed?"auto":"0px")}},beforeDestroy:function(){this.clear()},methods:{clear:function(){clearInterval(this._timer),clearTimeout(this._throttle),this._timer=null},start:function(){var t=this;return this.clear(),this.percent=0,this.reversed=!1,this.skipTimerCount=0,this.canSucceed=!0,this.throttle?this._throttle=setTimeout((function(){return t.startTimer()}),this.throttle):this.startTimer(),this},set:function(t){return this.show=!0,this.canSucceed=!0,this.percent=Math.min(100,Math.max(0,Math.floor(t))),this},get:function(){return this.percent},increase:function(t){return this.percent=Math.min(100,Math.floor(this.percent+t)),this},decrease:function(t){return this.percent=Math.max(0,Math.floor(this.percent-t)),this},pause:function(){return clearInterval(this._timer),this},resume:function(){return this.startTimer(),this},finish:function(){return this.percent=this.reversed?0:100,this.hide(),this},hide:function(){var t=this;return this.clear(),setTimeout((function(){t.show=!1,t.$nextTick((function(){t.percent=0,t.reversed=!1}))}),500),this},fail:function(){return this.canSucceed=!1,this},startTimer:function(){var t=this;this.show||(this.show=!0),void 0===this._cut&&(this._cut=1e4/Math.floor(this.duration)),this._timer=setInterval((function(){t.skipTimerCount>0?t.skipTimerCount--:(t.reversed?t.decrease(t._cut):t.increase(t._cut),t.continuous&&(t.percent>=100?(t.skipTimerCount=1,t.reversed=!t.reversed):t.percent<=0&&(t.skipTimerCount=1,t.reversed=!t.reversed)))}),100)}},render:function(t){var e=t(!1);return this.show&&(e=t("div",{staticClass:"nuxt-progress",class:{"nuxt-progress-notransition":this.skipTimerCount>0,"nuxt-progress-failed":!this.canSucceed},style:{width:this.percent+"%",left:this.left}})),e}}),N=(n(224),Object(E.a)(S,void 0,void 0,!1,null,null,null).exports),A=(n(226),n(231),n(233),{_default:Object(E.a)({},(function(){var t=this.$createElement,e=this._self._c||t;return e("div",[e("nuxt")],1)}),[],!1,null,null,null).exports}),D={head:{title:"img.jue.sh",meta:[{charset:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{hid:"description",name:"description",content:"免费图床,基于Telegraph的图片上传工具 IMG.NIPAO.COM"}],link:[{rel:"icon",type:"image/x-icon",href:"/favicon.ico"}],style:[],script:[]},render:function(t,e){var n=t("NuxtLoading",{ref:"loading"}),r=t(this.layout||"nuxt"),o=t("div",{domProps:{id:"__layout"},key:this.layoutName},[r]),c=t("transition",{props:{name:"layout",mode:"out-in"},on:{beforeEnter:function(t){window.$nuxt.$nextTick((function(){window.$nuxt.$emit("triggerScroll")}))}}},[o]);return t("div",{domProps:{id:"__nuxt"}},[n,c])},data:function(){return{isOnline:!0,layout:null,layoutName:""}},beforeCreate:function(){c.default.util.defineReactive(this,"nuxt",this.$options.nuxt)},created:function(){c.default.prototype.$nuxt=this,window.$nuxt=this,this.refreshOnlineStatus(),window.addEventListener("online",this.refreshOnlineStatus),window.addEventListener("offline",this.refreshOnlineStatus),this.error=this.nuxt.error,this.context=this.$options.context},mounted:function(){this.$loading=this.$refs.loading},watch:{"nuxt.err":"errorChanged"},computed:{isOffline:function(){return!this.isOnline}},methods:{refreshOnlineStatus:function(){void 0===window.navigator.onLine?this.isOnline=!0:this.isOnline=window.navigator.onLine},refresh:(k=Object(r.a)(regeneratorRuntime.mark((function t(){var e,n,r=this;return regeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if((e=Object(v.f)(this.$route)).length){t.next=3;break}return t.abrupt("return");case 3:return this.$loading.start(),n=e.map((function(t){var p=[];return t.$options.fetch&&p.push(Object(v.m)(t.$options.fetch,r.context)),t.$options.asyncData&&p.push(Object(v.m)(t.$options.asyncData,r.context).then((function(e){for(var n in e)c.default.set(t.$data,n,e[n])}))),Promise.all(p)})),t.prev=5,t.next=8,Promise.all(n);case 8:t.next=15;break;case 10:t.prev=10,t.t0=t.catch(5),this.$loading.fail(),Object(v.i)(t.t0),this.error(t.t0);case 15:this.$loading.finish();case 16:case"end":return t.stop()}}),t,this,[[5,10]])}))),function(){return k.apply(this,arguments)}),errorChanged:function(){this.nuxt.err&&this.$loading&&(this.$loading.fail&&this.$loading.fail(),this.$loading.finish&&this.$loading.finish())},setLayout:function(t){return t&&A["_"+t]||(t="default"),this.layoutName=t,this.layout=A["_"+t],this.layout},loadLayout:function(t){return t&&A["_"+t]||(t="default"),Promise.resolve(A["_"+t])}},components:{NuxtLoading:N}},L=(n(90),n(53)),M=n.n(L),I=n(174),B=n.n(I),z={setBaseURL:function(t){this.defaults.baseURL=t},setHeader:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"common",r=!0,o=!1,c=void 0;try{for(var f,l=(Array.isArray(n)?n:[n])[Symbol.iterator]();!(r=(f=l.next()).done);r=!0){var h=f.value;if(!e)return void delete this.defaults.headers[h][t];this.defaults.headers[h][t]=e}}catch(t){o=!0,c=t}finally{try{r||null==l.return||l.return()}finally{if(o)throw c}}},setToken:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"common",r=t?(e?e+" ":"")+t:null;this.setHeader("Authorization",r,n)},onRequest:function(t){this.interceptors.request.use((function(e){return t(e)||e}))},onResponse:function(t){this.interceptors.response.use((function(e){return t(e)||e}))},onRequestError:function(t){this.interceptors.request.use(void 0,(function(e){return t(e)||Promise.reject(e)}))},onResponseError:function(t){this.interceptors.response.use(void 0,(function(e){return t(e)||Promise.reject(e)}))},onError:function(t){this.onRequestError(t),this.onResponseError(t)},create:function(t){return J(B()(t,this.defaults))}},U=function(){var t=H[F];z["$"+t]=function(){return this[t].apply(this,arguments).then((function(t){return t&&t.data}))}},F=0,H=["request","delete","get","head","options","post","put","patch"];F has been deprecated and will be removed in Nuxt 3, please use instead")),m.a.render(t,e)}})),c.default.component(C.name,C),c.default.component("NChild",C),c.default.component(T.name,T),c.default.use(f.a,{keyName:"head",attribute:"data-n-head",ssrAttribute:"data-n-head-ssr",tagIDKeyName:"hid"});var ot={name:"page",mode:"out-in",appear:!1,appearClass:"appear",appearActiveClass:"appear-active",appearToClass:"appear-to"};function it(t){return at.apply(this,arguments)}function at(){return(at=Object(r.a)(regeneratorRuntime.mark((function t(e){var n,r,o,f,path,l;return regeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,new x.a(_);case 2:return n=t.sent,r=nt({router:n,nuxt:{defaultTransition:ot,transitions:[ot],setTransitions:function(t){return Array.isArray(t)||(t=[t]),t=t.map((function(t){return t=t?"string"==typeof t?Object.assign({},ot,{name:t}):Object.assign({},ot,t):ot})),this.$options.nuxt.transitions=t,t},err:null,dateErr:null,error:function(t){t=t||null,r.context._errored=Boolean(t),t=t?Object(v.l)(t):null;var n=this.nuxt||this.$options.nuxt;return n.dateErr=Date.now(),n.err=t,e&&(e.nuxt.error=t),t}}},D),o=e?e.next:function(t){return r.router.push(t)},e?f=n.resolve(e.url).route:(path=Object(v.d)(n.options.base,n.options.mode),f=n.resolve(path).route),t.next=8,Object(v.p)(r,{route:f,next:o,error:r.nuxt.error.bind(r),payload:e?e.payload:void 0,req:e?e.req:void 0,res:e?e.res:void 0,beforeRenderFns:e?e.beforeRenderFns:void 0,ssrContext:e});case 8:if(l=function(t,e){if(!t)throw new Error("inject(key, value) has no key provided");if(void 0===e)throw new Error("inject(key, value) has no value provided");r[t="$"+t]=e;var n="__nuxt_"+t+"_installed__";c.default[n]||(c.default[n]=!0,c.default.use((function(){Object.prototype.hasOwnProperty.call(c.default,t)||Object.defineProperty(c.default.prototype,t,{get:function(){return this.$root.$options[t]}})})))},"function"!=typeof Q){t.next=12;break}return t.next=12,Q(r.context,l);case 12:t.next=15;break;case 15:if("function"!=typeof Y){t.next=18;break}return t.next=18,Y(r.context,l);case 18:t.next=21;break;case 21:t.next=24;break;case 24:return t.abrupt("return",{app:r,router:n});case 25:case"end":return t.stop()}}),t)})))).apply(this,arguments)}},188:function(t,e,n){t.exports=n(189)},189:function(t,e,n){"use strict";n.r(e),function(t){n(86),n(90),n(49);var e=n(38),r=(n(63),n(183),n(5)),o=(n(132),n(134),n(33),n(19),n(94),n(95),n(123),n(199),n(206),n(208),n(0)),c=n(171),f=n(118),l=n(1),h=n(16),d=n(82);o.default.component(d.a.name,d.a),o.default.component("NLink",d.a),t.fetch||(t.fetch=c.a);var m,x,v=[],y=window.__NUXT__||{};Object.assign(o.default.config,{silent:!0,performance:!1});var w=o.default.config.errorHandler||console.error;function _(t,e,n){var r=function(component){var t=function(component,t){if(!component||!component.options||!component.options[t])return{};var option=component.options[t];if("function"==typeof option){for(var e=arguments.length,n=new Array(e>2?e-2:0),r=2;r0},canPrefetch:function(){var t=navigator.connection;return!(this.$nuxt.isOffline||t&&((t.effectiveType||"").includes("2g")||t.saveData))},getPrefetchComponents:function(){return this.$router.resolve(this.to,this.$route,this.append).resolved.matched.map((function(t){return t.components.default})).filter((function(t){return"function"==typeof t&&!t.options&&!t.__prefetched}))},prefetchLink:function(){if(this.canPrefetch()){f.unobserve(this.$el);var t=this.getPrefetchComponents(),e=!0,n=!1,r=void 0;try{for(var o,c=t[Symbol.iterator]();!(e=(o=c.next()).done);e=!0){var l=o.value,h=l();h instanceof Promise&&h.catch((function(){})),l.__prefetched=!0}}catch(t){n=!0,r=t}finally{try{e||null==c.return||c.return()}finally{if(n)throw r}}}}}}}},[[188,5,1,6]]]);
--------------------------------------------------------------------------------
/admin-imgtc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ImgTC | Admin
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | 编辑
110 | 复制
111 | 删除
112 |
113 |
114 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
141 |
142 |
143 |
144 |
145 | {{ item.metadata.fileName || item.name }}
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
186 |
191 | 当前浏览器不支持音频播放
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
249 |
250 | 加载更多
251 |
252 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
908 |
--------------------------------------------------------------------------------