Hoey笔记

和有趣的人做尽有趣的事


  • Home

  • Archives

  • Sitemap

  • Search

财务字段含义对照表

Posted on 2024-11-27

1.所有指标没有标注单位的都是个位,如资金项单位都是元,股本单位都是股。
2.所有的空值数据显示为0,以方便客户加减运算,非金融类指标在指标名称后有标注。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
-------------每股指标-----------------------------
1--基本每股收益
2--扣除非经常性损益每股收益
3--每股未分配利润
4--每股净资产
5--每股资本公积金
6--净资产收益率
7--每股经营现金流量
-------------资产负债表----------------------------
8.--货币资金
9.--交易性金融资产
10.--应收票据
11.--应收账款
12.--预付款项
13.--其他应收款
14.--应收关联公司款
15.--应收利息
16.--应收股利
17.--存货
18.--其中:消耗性生物资产
19.--一年内到期的非流动资产
20.--其他流动资产
21.--流动资产合计
22.--可供出售金融资产
23.--持有至到期投资
24.--长期应收款
25.--长期股权投资
26.--投资性房地产
27.--固定资产
28.--在建工程
29.--工程物资
30.--固定资产清理
31.--生产性生物资产
32.--油气资产
33.--无形资产
34.--开发支出
35.--商誉
36.--长期待摊费用
37.--递延所得税资产
38.--其他非流动资产
39.--非流动资产合计
40.--资产总计
41.--短期借款
42.--交易性金融负债
43.--应付票据
44.--应付账款
45.--预收款项
46.--应付职工薪酬
47.--应交税费
48.--应付利息
49.--应付股利
50.--其他应付款
51.--应付关联公司款
52.--一年内到期的非流动负债
53.--其他流动负债
54.--流动负债合计
55.--长期借款
56.--应付债券
57.--长期应付款
58.--专项应付款
59.--预计负债
60.--递延所得税负债
61.--其他非流动负债
62.--非流动负债合计
63.--负债合计
64.--实收资本(或股本)
65.--资本公积
66.--盈余公积
67.--减:库存股
68.--未分配利润
69.--少数股东权益
70.--外币报表折算价差
71.--非正常经营项目收益调整
72.--所有者权益(或股东权益)合计
73.--负债和所有者(或股东权益)合计
-------------利润表-----------------------------
74.--其中:营业收入
75.--其中:营业成本
76.--营业税金及附加
77.--销售费用
78.--管理费用
79.--勘探费用
80.--财务费用
81.--资产减值损失
82.--加:公允价值变动净收益
83.--投资收益
84.--其中:对联营企业和合营企业的投资收益
85.--影响营业利润的其他科目
86.--三、营业利润
87.--加:补贴收入
88.--营业外收入
89.--减:营业外支出
90.--其中:非流动资产处置净损失
91.--加:影响利润总额的其他科目
92.--四、利润总额
93.--减:所得税
94.--加:影响净利润的其他科目
95.--五、净利润
96.--归属于母公司所有者的净利润
97.--少数股东损益
------------------现金流量表---------------------
98.--销售商品、提供劳务收到的现金
99.--收到的税费返还
100.--收到其他与经营活动有关的现金
101.--经营活动现金流入小计
102.--购买商品、接受劳务支付的现金
103.--支付给职工以及为职工支付的现金
104.--支付的各项税费
105.--支付其他与经营活动有关的现金
106.--经营活动现金流出小计
107.--经营活动产生的现金流量净额
108.--收回投资收到的现金
109.--取得投资收益收到的现金
110.--处置固定资产、无形资产和其他长期资产收回的现金净额
111.--处置子公司及其他营业单位收到的现金净额
112.--收到其他与投资活动有关的现金
113.--投资活动现金流入小计
114.--购建固定资产、无形资产和其他长期资产支付的现金
115.--投资支付的现金
116.--取得子公司及其他营业单位支付的现金净额
117.--支付其他与投资活动有关的现金
118.--投资活动现金流出小计
119.--投资活动产生的现金流量净额
120.--吸收投资收到的现金
121.--取得借款收到的现金
122.--收到其他与筹资活动有关的现金
123.--筹资活动现金流入小计
124.--偿还债务支付的现金
125.--分配股利、利润或偿付利息支付的现金
126.--支付其他与筹资活动有关的现金
127.--筹资活动现金流出小计
128.--筹资活动产生的现金流量净额
129.--四、汇率变动对现金的影响
130.--四(2)、其他原因对现金的影响
131.--五、现金及现金等价物净增加额
132.--期初现金及现金等价物余额
133.--期末现金及现金等价物余额
134.--净利润
135.--加:资产减值准备
136.--固定资产折旧、油气资产折耗、生产性生物资产折旧
137.--无形资产摊销
138.--长期待摊费用摊销
139.--处置固定资产、无形资产和其他长期资产的损失
140.--固定资产报废损失
141.--公允价值变动损失
142.--财务费用
143.--投资损失
144.--递延所得税资产减少
145.--递延所得税负债增加
146.--存货的减少
147.--经营性应收项目的减少
148.--经营性应付项目的增加
149.--其他
150.--经营活动产生的现金流量净额2
151.--债务转为资本
152.--一年内到期的可转换公司债券
153.--融资租入固定资产
154.--现金的期末余额
155.--减:现金的期初余额
156.--加:现金等价物的期末余额
157.--减:现金等价物的期初余额
158.--现金及现金等价物净增加额
---------------------偿债能力分析------------------------
159.--流动比率(非金融类指标)
160.--速动比率(非金融类指标)
161.--现金比率(%)(非金融类指标)
162.--利息保障倍数(非金融类指标)
163.--非流动负债比率(%)(非金融类指标)
164.--流动负债比率(%)(非金融类指标)
165.--现金到期债务比率(%)(非金融类指标)
166.--有形资产净值债务率(%)
167.--权益乘数(%)
168.--股东的权益/负债合计(%)
169.--有形资产/负债合计(%)
170.--经营活动产生的现金流量净额/负债合计(%)(非金融类指标)
171.--EBITDA/负债合计(%)(非金融类指标)
---------------------经营效率分析------------------------
172.--应收帐款周转率(非金融类指标)
173.--存货周转率(非金融类指标)
174.--运营资金周转率(非金融类指标)
175.--总资产周转率(非金融类指标)
176.--固定资产周转率(非金融类指标)
177.--应收帐款周转天数(非金融类指标)
178.--存货周转天数(非金融类指标)
179.--流动资产周转率(非金融类指标)
180.--流动资产周转天数(非金融类指标)
181.--总资产周转天数(非金融类指标)
182.--股东权益周转率(非金融类指标)
---------------------发展能力分析------------------------
183.--营业收入增长率(%)
184.--净利润增长率(%)
185.--净资产增长率(%)
186.--固定资产增长率(%)
187.--总资产增长率(%)
188.--投资收益增长率(%)
189.--营业利润增长率(%)
190.--扣非每股收益同比(%)
191.--扣非净利润同比(%)
192.--暂无
---------------------获利能力分析------------------------
193.--成本费用利润率(%)
194.--营业利润率(非金融类指标)
195.--营业税金率(非金融类指标)
196.--营业成本率(非金融类指标)
197.--净资产收益率
198.--投资收益率
199.--销售净利率(%)
200.--总资产报酬率
201.--净利润率(非金融类指标)
202.--销售毛利率(%)(非金融类指标)
203.--三费比重(非金融类指标)
204.--管理费用率(非金融类指标)
205.--财务费用率(非金融类指标)
206.--扣除非经常性损益后的净利润
207.--息税前利润(EBIT)
208.--息税折旧摊销前利润(EBITDA)
209.--EBITDA/营业总收入(%)(非金融类指标)
---------------------资本结构分析---------------------
210.--资产负债率(%)
211.--流动资产比率(非金融类指标)
212.--货币资金比率(非金融类指标)
213.--存货比率(非金融类指标)
214.--固定资产比率
215.--负债结构比(非金融类指标)
216.--归属于母公司股东权益/全部投入资本(%)
217.--股东的权益/带息债务(%)
218.--有形资产/净债务(%)
---------------------现金流量分析---------------------
219.--每股经营性现金流(元)
220.--营业收入现金含量(%)(非金融类指标)
221.--经营活动产生的现金流量净额/经营活动净收益(%)
222.--销售商品提供劳务收到的现金/营业收入(%)
223.--经营活动产生的现金流量净额/营业收入
224.--资本支出/折旧和摊销
225.--每股现金流量净额(元)
226.--经营净现金比率(短期债务)(非金融类指标)
227.--经营净现金比率(全部债务)
228.--经营活动现金净流量与净利润比率
229.--全部资产现金回收率
---------------------单季度财务指标---------------------
230.--营业收入
231.--营业利润
232.--归属于母公司所有者的净利润
233.--扣除非经常性损益后的净利润
234.--经营活动产生的现金流量净额
235.--投资活动产生的现金流量净额
236.--筹资活动产生的现金流量净额
237.--现金及现金等价物净增加额
---------------------股本股东---------------------
238.--总股本
239.--已上市流通A股
240.--已上市流通B股
241.--已上市流通H股
242.--股东人数(户)
243.--第一大股东的持股数量
244.--十大流通股东持股数量合计(股)
245.--十大股东持股数量合计(股)
---------------------机构持股---------------------
246.--机构总量(家)
247.--机构持股总量(股)
248.--QFII机构数
249.--QFII持股量
250.--券商机构数
251.--券商持股量
252.--保险机构数
253.--保险持股量
254.--基金机构数
255.--基金持股量
256.--社保机构数
257.--社保持股量
258.--私募机构数
259.--私募持股量
260.--财务公司机构数
261.--财务公司持股量
262.--年金机构数
263.--年金持股量
---------------------新增指标---------------------
264.--十大流通股东中持有A股合计(股) [注:季度报告中,若股东同时持有非流通A股性质的股份(如同时持有流通A股和流通B股),指标264取的是包含同时持有非流通A股性质的流通股数]
265.--第一大流通股东持股量(股)
266.--自由流通股(股)[注:1.自由流通股=已流通A股-十大流通股东5%以上的A股;2.季度报告中,若股东同时持有非流通A股性质的股份(如同时持有流通A股和流通H股),5%以上的持股取的是不包含同时持有非流通A股性质的流通股数,结果可能偏大; 3.指标按报告期展示,新股在上市日的下个报告期才有数据]
267.--受限流通A股(股)
268.--一般风险准备(金融类)
269.--其他综合收益(利润表)
270.--综合收益总额(利润表)
271.--归属于母公司股东权益(资产负债表)
272.--银行机构数(家)(机构持股)
273.--银行持股量(股)(机构持股)
274.--一般法人机构数(家)(机构持股)
275.--一般法人持股量(股)(机构持股)
276.--近一年净利润(元)
277.--信托机构数(家)(机构持股)
278.--信托持股量(股)(机构持股)
279.--特殊法人机构数(家)(机构持股)
280.--特殊法人持股量(股)(机构持股)
281.--加权净资产收益率(每股指标)
282.--扣非每股收益(单季度财务指标)
283.--最近一年营业收入(万元)
284.--国家队持股数量(万股)[注:本指标统计包含汇金公司、证金公司、外汇管理局旗下投资平台、国家队基金、国开、养老金以及中科汇通等国家队机构持股数量]
285.--业绩预告-本期净利润同比增幅下限%[注:指标285至294展示未来一个报告期的数据。例,3月31日至6月29日这段时间内展示的是中报的数据;如果最新的财务报告后面有多个报告期的业绩预告/快报,只能展示最新的财务报告后面的一个报告期的业绩预告/快报]
286.--业绩预告-本期净利润同比增幅上限%
287.--业绩快报-归母净利润
288.--业绩快报-扣非净利润
289.--业绩快报-总资产
290.--业绩快报-净资产
291.--业绩快报-每股收益
292.--业绩快报-摊薄净资产收益率
293.--业绩快报-加权净资产收益率
294.--业绩快报-每股净资产
295.--应付票据及应付账款(资产负债表)
296.--应收票据及应收账款(资产负债表)
297.--递延收益(资产负债表-非流动负债)
298.--其他综合收益(资产负债表)
299.--其他权益工具(资产负债表)
300.--其他收益(利润表)
301.--资产处置收益(利润表)
302.--持续经营净利润(利润表)
303.--终止经营净利润(利润表)
304.--研发费用(利润表)
305.--其中:利息费用(利润表-财务费用)
306.--其中:利息收入(利润表-财务费用)
307.--近一年经营活动现金流净额
308.--近一年归母净利润(万元)
309.--近一年扣非净利润(万元)
310.--近一年现金净流量(万元)
311.--基本每股收益(单季度)
312.--营业总收入(单季度)(万元)
313.--业绩预告公告日期 [注:本指标展示未来一个报告期的数据。例,3月31日至6月29日这段时间内展示的是中报的数据;如果最新的财务报告后面有多个报告期的业绩预告/快报,只能展示最新的财务报告后面的一个报告期的业绩预告/快报的数据;公告日期格式为YYMMDD,例:190101代表2019年1月1日]
314.--财报公告日期 [注:日期格式为YYMMDD,例:190101代表2019年1月1日]
315.--业绩快报公告日期 [注:本指标展示未来一个报告期的数据。例,3月31日至6月29日这段时间内展示的是中报的数据;如果最新的财务报告后面有多个报告期的业绩预告/快报,只能展示最新的财务报告后面的一个报告期的业绩预告/快报的数据;公告日期格式为YYMMDD,例:190101代表2019年1月1日]
316.--近一年投资活动现金流净额(万元)
317.--业绩预告-本期净利润下限(万元)[注:指标317至318展示未来一个报告期的数据。例,3月31日至6月29日这段时间内展示的是中报的数据;如果最新的财务报告后面有多个报告期的业绩预告/快报,只能展示最新的财务报告后面的一个报告期的业绩预告/快报]
318.--业绩预告-本期净利润上限(万元)
319.--营业总收入TTM(万元)
320.--员工总数(人)
321.--每股企业自由现金流
322.--每股股东自由现金流

---------------------资产负债表新增指标---------------------
401.--专项储备(万元)
402.--结算备付金(万元)
403.--拆出资金(万元)
404.--发放贷款及垫款(万元)(流动资产科目)
405.--衍生金融资产(万元)
406.--应收保费(万元)
407.--应收分保账款(万元)
408.--应收分保合同准备金(万元)
409.--买入返售金融资产(万元)
410.--划分为持有待售的资产(万元)
411.--发放贷款及垫款(万元)(非流动资产科目)
412.--向中央银行借款(万元)
413.--吸收存款及同业存放(万元)
414.--拆入资金(万元)
415.--衍生金融负债(万元)
416.--卖出回购金融资产款(万元)
417.--应付手续费及佣金(万元)
418.--应付分保账款(万元)
419.--保险合同准备金(万元)
420.--代理买卖证券款(万元)
421.--代理承销证券款(万元)
422.--划分为持有待售的负债(万元)
423.--预计负债(万元)
424.--递延收益(万元)(流动负债科目,公告此科目的股票较少,大部分公司没有此数据)
425.--其中:优先股(万元)(非流动负债科目)
426.--永续债(万元)(非流动负债科目)
427.--长期应付职工薪酬(万元)
428.--其中:优先股(万元)(所有者权益科目)
429.--永续债(万元)(所有者权益科目)
430.--债权投资(万元)
431.--其他债权投资(万元)
432.--其他权益工具投资(万元)
433.--其他非流动金融资产(万元)
434.--合同负债(万元)
435.--合同资产(万元)
436.--其他资产(万元)
437.--应收款项融资(万元)
438.--使用权资产(万元)
439.--租赁负债(万元)

---------------------利润表新增指标---------------------
501.--稀释每股收益(元)
502.--营业总收入(万元)
503.--汇兑收益(万元)
504.--其中:归属于母公司综合收益(万元)
505.--其中:归属于少数股东综合收益(万元)
506.--利息收入(万元)
507.--已赚保费(万元)
508.--手续费及佣金收入(万元)
509.--利息支出(万元)
510.--手续费及佣金支出(万元)
511.--退保金(万元)
512.--赔付支出净额(万元)
513.--提取保险合同准备金净额(万元)
514.--保单红利支出(万元)
515.--分保费用(万元)
516.--其中:非流动资产处置利得(万元)
517.--信用减值损失(万元)
518.--净敞口套期收益(万元)
519.--营业总成本(万元)
520.--信用减值损失(万元、2019格式)
521.--资产减值损失(万元、2019格式)

---------------------现金流量表新增指标---------------------
561.--加:其他原因对现金的影响2(万元)(现金的期末余额科目)
562.--客户存款和同业存放款项净增加额(万元)
563.--向中央银行借款净增加额(万元)
564.--向其他金融机构拆入资金净增加额(万元)
565.--收到原保险合同保费取得的现金(万元)
566.--收到再保险业务现金净额(万元)
567.--保户储金及投资款净增加额(万元)
568.--处置以公允价值计量且其变动计入当期损益的金融资产净增加额(万元)
569.--收取利息、手续费及佣金的现金(万元)
570.--拆入资金净增加额(万元)
571.--回购业务资金净增加额(万元)
572.--客户贷款及垫款净增加额(万元)
573.--存放中央银行和同业款项净增加额(万元)
574.--支付原保险合同赔付款项的现金(万元)
575.--支付利息、手续费及佣金的现金(万元)
576.--支付保单红利的现金(万元)
577.--其中:子公司吸收少数股东投资收到的现金(万元)
578.--其中:子公司支付给少数股东的股利、利润(万元)
579.--投资性房地产的折旧及摊销(万元)
580.--信用减值损失(万元)

win python环境

Posted on 2024-11-19

image-20241119093134116

安装VSCode略

安装pyenv
https://blog.csdn.net/Auderiy/article/details/136248658
安装Python
python.org/ftp/python/3.7.9

注意事项:

  1. 安装python时选择自定义安装
  2. add path
  3. 为所有用户安装 all users

安装完成以后需要重启才可以使用

在vscode中使用虚拟环境

1
2
3
4
5
6
7
8
# 打开powershell 执行下面命令
set-ExecutionPolicy RemoteSigned

# 创建虚拟环境
python -m venv .venv
# 激活虚拟环境
.\.venv\Script\active

python 3.7 dbugger

https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-python/vsextensions/python/2022.6.0/vspackage

构建你的短链接

Posted on 2024-11-15

对短链服务架构研究一番后,小年就突然兴起,为何不自己动手做一个?

要实现一个简单易用的短链服务其实并不复杂,但是考虑到时间和维护成本,如果用Java、Go 来实现的话,可能会比较重、繁琐。

正巧小年最近在学习 React 和 Nextjs ,加上 Vercel 支持免费部署,刚好学以致用,尝试一点不一样的技术栈。

当然,重点是:免费!

按照小年的教程,只需要 10 分钟时间就可以免费部署一个自己的短链服务。

Step 1:Github Fork 项目

打开小年的 Github Repository:short-link,fork 到自己的仓库

Setp 2:注册 Vercel

登录 Vercel 官网注册账号,可以通过github账号关联登录。

Setp 3:创建项目

1、创建账号后,进入个人主页 Overview,创建项目

image.png

2、选中 Github Fork 的项目 short-link
image.png

3、这里默认选中 Next.js,点击 Deploy
image.png

Step 4:配置数据库

项目第一次部署后,虽然页面可以访问,但其实功能还不能正常运行,还需要配置Storage。

进到 Storage 创建数据库,类型选择 KV。

然后进入新创建的项目,进入 Storage ,关联刚刚新创建的数据库即可。
image.png

Step 5:重新部署

进入项目的部署标签页下,重新部署后,就可以直接使用了。
image.png

整个过程大概10min,就可以部署一套属于自己的短链服务。

vercel会为每个project自动生成一个域名,访问域名就能看到最终的效果页面啦~
image.png

SEO Google: 添加到 Search Console(有效解决零收录情况)

Posted on 2024-11-11

说明

如果发现搜索结果中一条记录都没有,那么在完成本文指引后,再等待 1 天,再去查询收录情况,就会发现提交的网站已经被收录了。

方法

  1. 打开控制台:https://search.google.com/search-console/welcome?hl=zh-cn
  2. 根据提示输入域名,添加 DNS 解析,我使用的验证方式是 CNAME,添加完后点击验证
  3. 点击左侧导航栏打开刚刚验证完成的网站,刚刚添加的网站,在 1 天后才能查看数据:
    ![image-20241111100407215](/Users/hoey/Library/Application Support/typora-user-images/image-20241111100407215.png)

查询是否已被收录

打开 Google,在搜索框输入以下内容(将 yourdomain.com 替换为你自己的顶级域名),然后点击搜索按钮:

1
site:yourdomain.com

深入了解 site: 搜索运算符

分析

根据 Google 收录后的条目,大概可以得知,GoogleBot 会先访问添加的网址,进而收集该入口页面的所有的超链接(),然后再访问这些超链接,再收集页面上超链接。

建议:

  • 路径层级最好不要超过两级,也就是说最大层级别超过 /a/b
  • 如果有些网址没有展示在页面上,那么就需要提交 站点地图 了

自定义图床OneDrive(二)

Posted on 2024-11-02

需求: E5保活+OneDrive(简称od)图床,由于篇幅太长,套域名就不写了。

前置准备:

  1. Debain12 & docker环境
  2. Windows (用来申请rclone访问OD Token)

安装rclone

1
2
3
sudo -v ; curl https://rclone.org/install.sh | sudo bash
# 安装rclone依赖
apt install fuse3

申请AZ客户端ID和密钥

rclone和od对接,需要”客户端ID”和”客户端密钥”这个到面板上申请一个。

访问Azure API管理面板登陆

image-20241102233146492

点击“新注册”注册一个应用程序。

image-20241102233214397

输入名称,勾选权限后注册应用。

image-20241102233240133

注册成功后将跳转到管理页面,记下图中所示的“应用程序(客户端) ID”,供将来挂载使用。

image-20241102233304789

此时点击“证书与密码”→“新客户端密码”,填写说明和截至期限后,添加密码。

image-20241102233419464

​ 添加密码后,我们记录密码值,供将来挂载使用。注意这里一定要将密码记录下来,因为它只显示一次。

image-20241102233439907

​ 接下来,点击“API权限”,为我们的api获取权限。Files中的权限全部勾选。

image-20241102233511198

至此,我们已经申请好了onedrive的api,目前我们已经得到了客户端ID以及客户端密钥。

rclone配置OD

到Windows下载rclone,执行下面的命令获取token

1
2
# windows系统下按win+R调出运行,输入“cmd”
rclone.exe authorize "onedrive" "客户端ID" "客户端密钥"

![image-20241102234244003](/Users/hoey/Library/Application Support/typora-user-images/image-20241102234244003.png)

把toekn存下来,后面要用,接下来来配置rclone 并挂在onedrive到本地/mnt/onedrive/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 配rclone注册远程连接
rclone config
n
onedrive
35 Microsoft OneDrive
客户端ID
客户端密钥
1 Microsoft Cloud Global
n No (default) 不进行高级配置
n No 不使用自动配置
配置上面从windows存储的token
1 OneDrive Personal or Business
y
y

最终成功结果,如果你哪一步跟不上可以参考这个文档申请onedrive api并使用rclone将其挂载为本地磁盘_rclone onedrive-CSDN博客参考上半部分就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir -p /mnt/onedrive/
vim /etc/systemd/system/rclone.service

# 里面的5G需要根据磁盘的大小设置,但是不能超过剩余磁盘空间

[Unit]
Description=rclone

[Service]
User=root
ExecStart=/usr/bin/rclone mount onedrive:/ /mnt/onedrive/ --allow-other --allow-non-empty --vfs-cache-mode writes --vfs-cache-max-size 5G --transfers 3
Restart=on-failure

[Install]
WantedBy=multi-user.target

sudo systemctl daemon-reload
sudo systemctl start rclone
sudo systemctl enable rclone
sudo systemctl status rclone

lsky

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mkdir -p /opt/docker/lsky-pro/lsky
cd /opt/docker/lsky-pro

vim docker-compose.yml
# 18088 & 18089可以自定义
services:
lsky-pro:
image: hisatri/lsky:latest
container_name: lsky-pro
restart: unless-stopped
ports:
- "18088:8088"
- "18089:8089"
volumes:
- $PWD/lsky:/var/www/html
- /mnt/onedrive:/onedrive
environment:
- HTTPS_PORT=8088
- WEB_PORT=8089

docker-compose up -d

访问localhost:18089

数据库选择sqllite,存储目录留空不填写,自己设置个邮箱和密码。

角色组

image-20241102235558735

存储策略

image-20241102235626568

picgo

插件->lankong

image-20241102235818645

设置

![image-20241102235848350](/Users/hoey/Library/Application Support/typora-user-images/image-20241102235848350.png)

Auth token的获取方法:

照着这个放一个post请求就可以了。

http://pic.yihao.de/api/v1/tokens?email=&password=

image-20241103004820420

微软E5账号介绍

Posted on 2024-10-31

image-20241031101825149

Microsoft 365 E5是一款综合性的商业应用套件,它包含一系列的生产力应用和服务。E5版特别提供了一些高级的安全、合规性、语音和分析能力【7†source】。E5包括以下的应用和服务:

  • Word
  • Excel
  • PowerPoint
  • Outlook
  • OneNote
  • SharePoint
  • OneDrive (5T)
  • Microsoft Teams
  • Power BI Pro
  • Windows【9+source】

喜当爹

Posted on 2024-10-27

image-20241027142706017

意不意外、惊不惊喜,就是这么快。

自定义图床

Posted on 2024-10-27

image-20241027141114973

之前用的阿里云图床,后来产生的费用让人难以维持,下面用TG+CF的方案实现一个图床,自己试了一下很好用

https://img.yihao.de/

一、GitHub

按照github的代码部署一下,操作如readme一样

0-RTT/telegraph

二、 worder.js

我这边自行稍微改造了一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
export default {
async fetch(request, env) {
const { pathname } = new URL(request.url);
const domain = env.DOMAIN;
const DATABASE = env.DATABASE;
const USERNAME = env.USERNAME;
const PASSWORD = env.PASSWORD;
const adminPath = env.ADMIN_PATH;
const enableAuth = env.ENABLE_AUTH === 'true';
const TG_BOT_TOKEN = env.TG_BOT_TOKEN;
const TG_CHAT_ID = env.TG_CHAT_ID;

switch (pathname) {
case '/':
return await handleRootRequest(request, USERNAME, PASSWORD, enableAuth);
case `/${adminPath}`:
return await handleAdminRequest(DATABASE, request, USERNAME, PASSWORD);
case '/upload':
return request.method === 'POST' ? await handleUploadRequest(request, DATABASE, enableAuth, USERNAME, PASSWORD, domain, TG_BOT_TOKEN, TG_CHAT_ID) : new Response('Method Not Allowed', { status: 405 });
case '/bing-images':
return handleBingImagesRequest();
case '/delete-images':
return handleDeleteImagesRequest(request, DATABASE);
default:
return await handleImageRequest(request, DATABASE, TG_BOT_TOKEN);
}
}
};

let isAuthenticated = false;

function authenticate(request, USERNAME, PASSWORD) {
const authHeader = request.headers.get('Authorization');
if (!authHeader) return false;
return isValidCredentials(authHeader, USERNAME, PASSWORD);
}

async function handleRootRequest(request, USERNAME, PASSWORD, enableAuth) {
const cache = caches.default;
const cacheKey = new Request(request.url);
if (enableAuth) {
if (!authenticate(request, USERNAME, PASSWORD)) {
return new Response('Unauthorized', { status: 401, headers: { 'WWW-Authenticate': 'Basic realm="Admin"' } });
}
}
const cachedResponse = await cache.match(cacheKey);
if (cachedResponse) {
return cachedResponse;
}
const response = new Response(`
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Telegraph图床-基于Workers的图床服务">
<meta name="keywords" content="Telegraph图床,Workers图床, Cloudflare, Workers,telegra.ph, 图床">
<title>Telegraph图床-基于Workers的图床服务</title>
<link rel="icon" href="https://p1.meituan.net/csc/c195ee91001e783f39f41ffffbbcbd484286.ico" type="image/x-icon">
<link href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/twitter-bootstrap/4.6.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/bootstrap-fileinput/5.2.7/css/fileinput.min.css" rel="stylesheet" />
<link href="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/toastr.js/2.1.4/toastr.min.css" rel="stylesheet" />
<link href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/5.15.4/css/all.min.css" type="text/css" rel="stylesheet" />
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
position: relative;
}
.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
z-index: -1;
transition: opacity 1s ease-in-out;
opacity: 1;
}
.card {
background-color: rgba(255, 255, 255, 0.8);
border: none;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
padding: 20px;
width: 90%;
max-width: 400px;
text-align: center;
margin: 0 auto;
position: relative;
}
.uniform-height {
margin-top: 20px;
}
#viewCacheBtn {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
color: rgba(0, 0, 0, 0.1);
cursor: pointer;
font-size: 24px;
transition: color 0.3s ease;
}
#viewCacheBtn:hover {
color: rgba(0, 0, 0, 0.4);
}
#cacheContent {
margin-top: 20px;
max-height: 200px;
border-radius: 5px;
overflow-y: auto;
}
.cache-title {
text-align: left;
margin-bottom: 10px;
}
.cache-item {
display: block;
cursor: pointer;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: background-color 0.3s ease;
text-align: left;
padding: 10px;
}
.cache-item:hover {
background-color: #e9ecef;
}
.project-link {
font-size: 14px;
text-align: center;
margin-top: 5px;
margin-bottom: 0;
}
textarea.form-control {
max-height: 200px;
overflow-y: hidden;
resize: none;
}
</style>
</head>
<body>
<div class="background" id="background"></div>
<div class="card">
<div class="title">Telegraph图床</div>
<button type="button" class="btn" id="viewCacheBtn" title="查看历史记录"><i class="fas fa-clock"></i></button>
<div class="card-body">
<form id="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
<div class="file-input-container">
<input id="fileInput" name="file" type="file" class="form-control-file" data-browse-on-zone-click="true" multiple>
</div>
<div class="form-group mb-3 uniform-height" style="display: none;">
<button type="button" class="btn btn-light mr-2" id="urlBtn">URL</button>
<button type="button" class="btn btn-light mr-2" id="bbcodeBtn">BBCode</button>
<button type="button" class="btn btn-light" id="markdownBtn">Markdown</button>
</div>
<div class="form-group mb-3 uniform-height" style="display: none;">
<textarea class="form-control" id="fileLink" readonly></textarea>
</div>
<div id="cacheContent" style="display: none;"></div>
</form>
</div>
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js" type="application/javascript"></script>
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/bootstrap-fileinput/5.2.7/js/fileinput.min.js" type="application/javascript"></script>
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/bootstrap-fileinput/5.2.7/js/locales/zh.min.js" type="application/javascript"></script>
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/toastr.js/2.1.4/toastr.min.js" type="application/javascript"></script>
<script>
async function fetchBingImages() {
const response = await fetch('/bing-images');
const data = await response.json();
return data.data.map(image => image.url);
}

async function setBackgroundImages() {
const images = await fetchBingImages();
const backgroundDiv = document.getElementById('background');
if (images.length > 0) {
backgroundDiv.style.backgroundImage = 'url(' + images[0] + ')';
}
let index = 0;
let currentBackgroundDiv = backgroundDiv;
setInterval(() => {
const nextIndex = (index + 1) % images.length;
const nextBackgroundDiv = document.createElement('div');
nextBackgroundDiv.className = 'background next';
nextBackgroundDiv.style.backgroundImage = 'url(' + images[nextIndex] + ')';
document.body.appendChild(nextBackgroundDiv);
nextBackgroundDiv.style.opacity = 0;
setTimeout(() => {
nextBackgroundDiv.style.opacity = 1;
}, 50);
setTimeout(() => {
document.body.removeChild(currentBackgroundDiv);
currentBackgroundDiv = nextBackgroundDiv;
index = nextIndex;
}, 1000);
}, 5000);
}

$(document).ready(function() {
let originalImageURLs = [];
let isCacheVisible = false;
initFileInput();
setBackgroundImages();

function initFileInput() {
$("#fileInput").fileinput({
theme: 'fa',
language: 'zh',
browseClass: "btn btn-primary",
removeClass: "btn btn-danger",
showUpload: false,
showPreview: false,
}).on('filebatchselected', handleFileSelection)
.on('fileclear', handleFileClear);
}

async function handleFileSelection() {
const files = $('#fileInput')[0].files;
for (let i = 0; i < files.length; i++) {
await uploadFile(files[i]);
}
}

async function uploadFile(file) {
try {
toastr.info('上传中...', '', { timeOut: 0 });
const interfaceInfo = {
acceptTypes: 'image/*,video/*',
maxFileSize: 20 * 1024 * 1024
};
const acceptedTypes = interfaceInfo.acceptTypes.split(',');
const isAcceptedType = acceptedTypes.some(type => {
return type.includes('*') ? file.type.startsWith(type.split('/')[0]) : file.type === type;
});
if (!isAcceptedType) {
toastr.error('仅支持图片或视频格式的文件。');
return;
}
if (file.size > interfaceInfo.maxFileSize) {
if (file.type.startsWith('video/') || file.type === 'image/gif') {
toastr.error('文件必须≤20MB');
return;
} else {
toastr.info('正在压缩...', '', { timeOut: 0 });
const compressedFile = await compressImage(file);
file = compressedFile;
}
}
const formData = new FormData($('#uploadForm')[0]);
formData.set('file', file, file.name);
const uploadResponse = await fetch('/upload', { method: 'POST', body: formData });
const responseData = await handleUploadResponse(uploadResponse);
if (responseData.error) {
toastr.error(responseData.error);
} else {
originalImageURLs.push(responseData.data);
$('#fileLink').val(originalImageURLs.join('\\n\\n'));
$('.form-group').show();
adjustTextareaHeight($('#fileLink')[0]);
toastr.success('文件上传成功!');
saveToLocalCache(responseData.data, file.name);
}
} catch (error) {
console.error('处理文件时出现错误:', error);
$('#fileLink').val('文件处理失败!');
toastr.error('文件处理失败!');
} finally {
toastr.clear();
}
}

async function handleUploadResponse(response) {
if (response.ok) {
return await response.json();
} else {
const errorData = await response.json();
return { error: errorData.error };
}
}

$(document).on('paste', function(event) {
const clipboardData = event.originalEvent.clipboardData;
if (clipboardData && clipboardData.items) {
for (let i = 0; i < clipboardData.items.length; i++) {
const item = clipboardData.items[i];
if (item.kind === 'file') {
const pasteFile = item.getAsFile();
uploadFile(pasteFile);
break;
}
}
}
});

async function compressImage(file, quality = 0.5, maxResolution = 20000000) {
return new Promise((resolve) => {
const image = new Image();
image.onload = () => {
const width = image.width;
const height = image.height;
const resolution = width * height;
let scale = 1;
if (resolution > maxResolution) {
scale = Math.sqrt(maxResolution / resolution);
}
const targetWidth = Math.round(width * scale);
const targetHeight = Math.round(height * scale);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = targetWidth;
canvas.height = targetHeight;
ctx.drawImage(image, 0, 0, targetWidth, targetHeight);
canvas.toBlob((blob) => {
const compressedFile = new File([blob], file.name, { type: 'image/jpeg' });
toastr.success('图片压缩成功!');
resolve(compressedFile);
}, 'image/jpeg', quality);
};
const reader = new FileReader();
reader.onload = (event) => {
image.src = event.target.result;
};
reader.readAsDataURL(file);
});
}

$('#urlBtn, #bbcodeBtn, #markdownBtn').on('click', function() {
const fileLinks = originalImageURLs.map(url => url.trim()).filter(url => url !== '');
if (fileLinks.length > 0) {
let formattedLinks = '';
switch ($(this).attr('id')) {
case 'urlBtn':
formattedLinks = fileLinks.join('\\n\\n');
break;
case 'bbcodeBtn':
formattedLinks = fileLinks.map(url => '[img]' + url + '[/img]').join('\\n\\n');
break;
case 'markdownBtn':
formattedLinks = fileLinks.map(url => '![image](' + url + ')').join('\\n\\n');
break;
default:
formattedLinks = fileLinks.join('\\n');
}
$('#fileLink').val(formattedLinks);
adjustTextareaHeight($('#fileLink')[0]);
copyToClipboardWithToastr(formattedLinks);
}
});

function handleFileClear(event) {
$('#fileLink').val('');
adjustTextareaHeight($('#fileLink')[0]);
hideButtonsAndTextarea();
originalImageURLs = [];
}

function adjustTextareaHeight(textarea) {
textarea.style.height = '1px';
textarea.style.height = (textarea.scrollHeight > 200 ? 200 : textarea.scrollHeight) + 'px';

if (textarea.scrollHeight > 200) {
textarea.style.overflowY = 'auto';
} else {
textarea.style.overflowY = 'hidden';
}
}

function copyToClipboardWithToastr(text) {
const input = document.createElement('textarea');
input.value = text;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
toastr.success('已复制到剪贴板', '', { timeOut: 300 });
}

function hideButtonsAndTextarea() {
$('#urlBtn, #bbcodeBtn, #markdownBtn, #fileLink').parent('.form-group').hide();
}

function saveToLocalCache(url, fileName) {
const timestamp = new Date().toLocaleString('zh-CN', { hour12: false });
const cacheData = JSON.parse(localStorage.getItem('uploadCache')) || [];
cacheData.push({ url, fileName, timestamp });
localStorage.setItem('uploadCache', JSON.stringify(cacheData));
}

$('#viewCacheBtn').on('click', function() {
const cacheData = JSON.parse(localStorage.getItem('uploadCache')) || [];
const cacheContent = $('#cacheContent');
cacheContent.empty();
if (isCacheVisible) {
cacheContent.hide();
$('#fileLink').val('');
$('#fileLink').parent('.form-group').hide();
isCacheVisible = false;
} else {
if (cacheData.length > 0) {
cacheData.reverse();
cacheData.forEach((item) => {
const listItem = $('<div class="cache-item"></div>')
.text(item.timestamp + ' - ' + item.fileName)
.data('url', item.url);
cacheContent.append(listItem);
cacheContent.append('<br>');
});
cacheContent.show();
} else {
cacheContent.append('<div>还没有记录哦!</div>').show();
}
isCacheVisible = true;
}
});

$(document).on('click', '.cache-item', function() {
const url = $(this).data('url');
originalImageURLs = [];
$('#fileLink').val('');
originalImageURLs.push(url);
$('#fileLink').val(originalImageURLs.map(url => url.trim()).join('\\n\\n'));
$('.form-group').show();
adjustTextareaHeight($('#fileLink')[0]);
});
});
</script>
</body>
</html>
`, { headers: { 'Content-Type': 'text/html;charset=UTF-8' } });
await cache.put(cacheKey, response.clone());
return response;
}

async function handleAdminRequest(DATABASE, request, USERNAME, PASSWORD) {
if (!authenticate(request, USERNAME, PASSWORD)) {
return new Response('Unauthorized', { status: 401, headers: { 'WWW-Authenticate': 'Basic realm="Admin"' } });
}
return await generateAdminPage(DATABASE);
}

function isValidCredentials(authHeader, USERNAME, PASSWORD) {
const base64Credentials = authHeader.split(' ')[1];
const credentials = atob(base64Credentials).split(':');
const username = credentials[0];
const password = credentials[1];
return username === USERNAME && password === PASSWORD;
}

async function generateAdminPage(DATABASE) {
const mediaData = await fetchMediaData(DATABASE);
const mediaHtml = mediaData.map(({ url }) => {
const fileExtension = url.split('.').pop().toLowerCase();
const timestamp = url.split('/').pop().split('.')[0];
if (fileExtension === 'mp4') {
return `
<div class="media-container" data-key="${url}" onclick="toggleImageSelection(this)">
<div class="media-type">视频</div>
<video class="gallery-video" style="width: 100%; height: 100%; object-fit: contain;" data-src="${url}" controls>
<source src="${url}" type="video/mp4">
您的浏览器不支持视频标签。
</video>
<div class="upload-time">上传时间: ${new Date(parseInt(timestamp)).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}</div>
</div>
`;
} else {
return `
<div class="image-container" data-key="${url}" onclick="toggleImageSelection(this)">
<img data-src="${url}" alt="Image" class="gallery-image lazy">
<div class="upload-time">上传时间: ${new Date(parseInt(timestamp)).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}</div>
</div>
`;
}
}).join('');

const html = `
<!DOCTYPE html>
<html>
<head>
<title>图库</title>
<link rel="icon" href="https://p1.meituan.net/csc/c195ee91001e783f39f41ffffbbcbd484286.ico" type="image/x-icon">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px;
}
.header {
position: sticky;
top: 0;
background-color: #ffffff;
z-index: 1000;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.image-container, .media-container {
position: relative;
overflow: hidden;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
aspect-ratio: 1 / 1;
transition: transform 0.3s, box-shadow 0.3s;
}
.media-type {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 5px;
border-radius: 5px;
font-size: 14px;
z-index: 10;
cursor: pointer;
}
.image-container .upload-time, .media-container .upload-time {
position: absolute;
bottom: 10px;
left: 10px;
background-color: rgba(255, 255, 255, 0.7);
padding: 5px;
border-radius: 5px;
color: #000;
font-size: 14px;
z-index: 10;
display: none;
}
.image-container:hover, .media-container:hover {
transform: scale(1.05);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}
.gallery-image {
width: 100%;
height: 100%;
object-fit: contain;
transition: opacity 0.3s;
opacity: 0;
}
.gallery-image.loaded {
opacity: 1;
}
.media-container.selected, .image-container.selected {
border: 2px solid #007bff;
background-color: rgba(0, 123, 255, 0.1);
}
.footer {
margin-top: 20px;
text-align: center;
font-size: 18px;
color: #555;
}
.delete-button {
background-color: #ff4d4d;
color: white;
border: none;
border-radius: 5px;
padding: 10px 15px;
cursor: pointer;
transition: background-color 0.3s;
width: auto;
}
.delete-button:hover {
background-color: #ff1a1a;
}
.hidden {
display: none;
}
@media (max-width: 600px) {
.gallery {
grid-template-columns: repeat(2, 1fr);
}
.header {
flex-direction: row;
align-items: center;
}
.header-right {
margin-left: auto;
}
.footer {
font-size: 16px;
}
.delete-button {
width: 100%;
margin-top: 10px;
}
}
</style>
<script>
let selectedCount = 0;
const selectedKeys = new Set();
function toggleImageSelection(container) {
const key = container.getAttribute('data-key');
container.classList.toggle('selected');
const uploadTime = container.querySelector('.upload-time');
if (container.classList.contains('selected')) {
selectedKeys.add(key);
selectedCount++;
uploadTime.style.display = 'block';
} else {
selectedKeys.delete(key);
selectedCount--;
uploadTime.style.display = 'none';
}
updateDeleteButton();
}
function updateDeleteButton() {
const deleteButton = document.getElementById('delete-button');
const countDisplay = document.getElementById('selected-count');
countDisplay.textContent = selectedCount;
const headerRight = document.querySelector('.header-right');
if (selectedCount > 0) {
headerRight.classList.remove('hidden');
} else {
headerRight.classList.add('hidden');
}
}
async function deleteSelectedImages() {
if (selectedKeys.size === 0) return;
const response = await fetch('/delete-images', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(Array.from(selectedKeys))
});
if (response.ok) {
alert('选中的媒体已删除');
location.reload();
} else {
alert('删除失败');
}
}
document.addEventListener('DOMContentLoaded', () => {
const images = document.querySelectorAll('.gallery-image[data-src]');
const options = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.onload = () => img.classList.add('loaded');
observer.unobserve(img);
}
});
}, options);
images.forEach(image => {
imageObserver.observe(image);
});
});
</script>
</head>
<body>
<div class="header">
<div class="header-left">
<span>媒体文件 ${mediaData.length} 个</span>
<span>已选中: <span id="selected-count">0</span>个</span>
</div>
<div class="header-right hidden">
<button id="delete-button" class="delete-button" onclick="deleteSelectedImages()">删除选中</button>
</div>
</div>
<div class="gallery">
${mediaHtml}
</div>
<div class="footer">
到底啦
</div>
</body>
</html>
`;
return new Response(html, { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } });
}

async function fetchMediaData(DATABASE) {
const result = await DATABASE.prepare('SELECT url, fileId FROM media').all();
const mediaData = result.results.map(row => {
const timestamp = parseInt(row.url.split('/').pop().split('.')[0]);
return { fileId: row.fileId, url: row.url, timestamp: timestamp };
});
mediaData.sort((a, b) => b.timestamp - a.timestamp);
return mediaData.map(({ fileId, url }) => ({ fileId, url }));
}

async function handleUploadRequest(request, DATABASE, enableAuth, USERNAME, PASSWORD, domain, TG_BOT_TOKEN, TG_CHAT_ID) {
try {
const formData = await request.formData();
const file = formData.get('file');
if (!file) throw new Error('缺少文件');
if (enableAuth && !authenticate(request, USERNAME, PASSWORD)) {
return new Response('Unauthorized', { status: 401, headers: { 'WWW-Authenticate': 'Basic realm="Admin"' } });
}
const uploadFormData = new FormData();
uploadFormData.append("chat_id", TG_CHAT_ID);
let fileId;
if (file.type.startsWith('image/gif')) {
const newFileName = file.name.replace(/\.gif$/, '.jpeg');
const newFile = new File([file], newFileName, { type: 'image/jpeg' });
uploadFormData.append("document", newFile);
} else {
uploadFormData.append("document", file);
}
const telegramResponse = await fetch(`https://api.telegram.org/bot${TG_BOT_TOKEN}/sendDocument`, { method: 'POST', body: uploadFormData });
if (!telegramResponse.ok) {
const errorData = await telegramResponse.json();
throw new Error(errorData.description || '上传到 Telegram 失败');
}
const responseData = await telegramResponse.json();
if (responseData.result.video) fileId = responseData.result.video.file_id;
else if (responseData.result.document) fileId = responseData.result.document.file_id;
else if (responseData.result.sticker) fileId = responseData.result.sticker.file_id;
else throw new Error('返回的数据中没有文件 ID');
const fileExtension = file.name.split('.').pop();
const timestamp = Date.now();
const imageURL = `https://${domain}/${timestamp}.${fileExtension}`;
await DATABASE.prepare('INSERT INTO media (url, fileId) VALUES (?, ?) ON CONFLICT(url) DO NOTHING').bind(imageURL, fileId).run();
return new Response(JSON.stringify({ data: imageURL }), { status: 200, headers: { 'Content-Type': 'application/json' } });
} catch (error) {
console.error('内部服务器错误:', error);
return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } });
}
}

async function handleImageRequest(request, DATABASE, TG_BOT_TOKEN) {
const requestedUrl = request.url;
const cache = caches.default;
const cacheKey = new Request(requestedUrl);
const cachedResponse = await cache.match(cacheKey);
if (cachedResponse) return cachedResponse;
const result = await DATABASE.prepare('SELECT fileId FROM media WHERE url = ?').bind(requestedUrl).first();
if (result) {
const fileId = result.fileId;
const getFileResponse = await fetch(`https://api.telegram.org/bot${TG_BOT_TOKEN}/getFile?file_id=${fileId}`);
if (!getFileResponse.ok) return new Response(null, { status: 404 });
const fileData = await getFileResponse.json();
const filePath = fileData.result.file_path;
const telegramFileUrl = `https://api.telegram.org/file/bot${TG_BOT_TOKEN}/${filePath}`;
const response = await fetch(telegramFileUrl);
if (response.ok) {
const fileExtension = requestedUrl.split('.').pop().toLowerCase();
let contentType = 'text/plain';
if (fileExtension === 'jpg' || fileExtension === 'jpeg') contentType = 'image/jpeg';
if (fileExtension === 'png') contentType = 'image/png';
if (fileExtension === 'gif') contentType = 'image/gif';
if (fileExtension === 'webp') contentType = 'image/webp';
if (fileExtension === 'mp4') contentType = 'video/mp4';
const headers = new Headers(response.headers);
headers.set('Content-Type', contentType);
headers.set('Content-Disposition', 'inline');
const responseToCache = new Response(response.body, { status: response.status, headers });
await cache.put(cacheKey, responseToCache.clone());
return responseToCache;
}
}
const notFoundResponse = new Response(null, { status: 404 });
await cache.put(cacheKey, notFoundResponse.clone());
return notFoundResponse;
}

async function handleBingImagesRequest(request) {
const cache = caches.default;
const cacheKey = new Request('https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=5');
const cachedResponse = await cache.match(cacheKey);
if (cachedResponse) return cachedResponse;
const res = await fetch(cacheKey);
const bingData = await res.json();
const images = bingData.images.map(image => ({ url: `https://www.dmoe.cc/random.php` }));
const returnData = { status: true, message: "操作成功", data: images };
const response = new Response(JSON.stringify(returnData), { status: 200, headers: { 'Content-Type': 'application/json' } });
await cache.put(cacheKey, response.clone());
return response;
}

async function handleDeleteImagesRequest(request, DATABASE) {
if (request.method !== 'POST') {
return new Response('Method Not Allowed', { status: 405 });
}
try {
const keysToDelete = await request.json();
if (!Array.isArray(keysToDelete) || keysToDelete.length === 0) {
return new Response(JSON.stringify({ message: '没有要删除的项' }), { status: 400 });
}
const placeholders = keysToDelete.map(() => '?').join(',');
const result = await DATABASE.prepare(`DELETE FROM media WHERE url IN (${placeholders})`).bind(...keysToDelete).run();
if (result.changes === 0) {
return new Response(JSON.stringify({ message: '未找到要删除的项' }), { status: 404 });
}
const cache = caches.default;
for (const url of keysToDelete) {
const cacheKey = new Request(url);
const cachedResponse = await cache.match(cacheKey);
if (cachedResponse) {
await cache.delete(cacheKey);
}
}
return new Response(JSON.stringify({ message: '删除成功' }), { status: 200 });
} catch (error) {
return new Response(JSON.stringify({ error: '删除失败', details: error.message }), { status: 500 });
}
}

三、 关于背景修改

下面是两个可用的动漫背景随机图,可以提供修改。

1
const images = bingData.images.map(image => ({ url: `https://www.dmoe.cc/random.php` }));

这行代码里面的url可以改掉就行了。

动漫
www.dmoe.cc/random.php
api.mtyqx.cn/tapi/random.php (挺好看的动漫)

分享几个公用的高清壁纸图片的API | LearnKu 产品论坛

四、 关于PicGo

到插件中下载一个【自定义图床】插件,按照下面设置即可

image-20241027141000857

Netcup注册

Posted on 2024-10-25

Netcup可以注册后缀为de的域名一年1.32欧元,续费一样相当划算

image-20241025090250956

另外Netcup有0.84欧元/月的VPS套餐,每个账户只允许申请一台。

image-20241025090506316

探针如下:

image-20241025090705371

1.家宽直连,最好在下午4点到早上6点去试,这样能快一点,德国人在上班。用这个链接去买,感谢justwe佬的分享,应该不是aff

1
2
3
1o:https://www.netcup.de/bestellen/produkt.php?produkt=3422
2o:https://www.netcup.de/bestellen/produkt.php?produkt=3423
4o:https://www.netcup.de/bestellen/produkt.php?produkt=3424

2.一直往下点就行,不行就翻译一下,选择注册帐号,填入你的真实信息,地址不能有“,”全英文,地址选中国,公司可以不填
3.会发一封邮件说工作人员正在审核,问你要不要付款,你可以取消之类的,如果你用家宽的话等5分钟左右会收到两封连在一起的邮件,一封给了你帐号密码,另一封让你去验证身份,你打开验证身份即可,注意一定要在第一次就选择预付款,不要选验证身份
4.去https://www.servercontrolpanel.de/SCP/Home 登录,会发二步验证到你的邮箱,去billing付款,信用卡或者paypal,等机器开通,done!

全程顺利的话半小时解决,我等机器开通等了1个小时,现在只要付钱就能过了,方便多了

findbook的使用方法

Posted on 2024-09-19

我们在searching图书的时候,下载时如果长时间停留0%,那一定是你的网关设置的有问题,只需要按照下面配置即可。

  1. 访问下面地址,查看自己的网络状态

https://ipfs.github.io/public-gateway-checker/

image-20240919164656261

  1. 将域名复制编辑

    1
    2
    3
    4
    https://ipfs.runfission.com
    https://4everland.io
    https://gateway.pinata.cloud
    https://trustless-gateway.link

​ 将上面的内容复制到页面右上角的⚙️中去,然后保存。

image-20240919164811500

  1. 重新尝试下载
<123…6>

54 posts
© 2025 Hoey