add favourite

This commit is contained in:
BennyThink
2021-04-04 14:08:32 +08:00
parent c9e84f293c
commit 8d90cbafcf
13 changed files with 953 additions and 27 deletions

3
.gitattributes vendored
View File

@@ -10,8 +10,9 @@ web/css/** linguist-vendored
web/fonts/* linguist-vendored
web/img/* linguist-vendored
web/js/* linguist-vendored
web/js/analytics.js -linguist-vendored
web/404.html linguist-vendored
web/resource.html linguist-vendored
web/js/common.js -linguist-vendored
tests/data/* linguist-vendored

View File

@@ -50,6 +50,9 @@ yyets_offline - 人人影视离线数据
本网站永久免费,并且没有任何限制。
![](assets/2.png)
支持收藏功能,会跨设备同步
![](assets/like.png)
## 指定字幕组搜索
目前只支持YYeTsOffline和ZimuxiaOnline

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 314 KiB

BIN
assets/like.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

697
web/css/noty.css vendored Normal file
View File

@@ -0,0 +1,697 @@
.noty_layout_mixin, #noty_layout__top, #noty_layout__topLeft, #noty_layout__topCenter, #noty_layout__topRight, #noty_layout__bottom, #noty_layout__bottomLeft, #noty_layout__bottomCenter, #noty_layout__bottomRight, #noty_layout__center, #noty_layout__centerLeft, #noty_layout__centerRight {
position: fixed;
margin: 0;
padding: 0;
z-index: 9999999;
-webkit-transform: translateZ(0) scale(1, 1);
transform: translateZ(0) scale(1, 1);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-font-smoothing: subpixel-antialiased;
filter: blur(0);
-webkit-filter: blur(0);
max-width: 90%; }
#noty_layout__top {
top: 0;
left: 5%;
width: 90%; }
#noty_layout__topLeft {
top: 20px;
left: 20px;
width: 325px; }
#noty_layout__topCenter {
top: 5%;
left: 50%;
width: 325px;
-webkit-transform: translate(-webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__topRight {
top: 20px;
right: 20px;
width: 325px; }
#noty_layout__bottom {
bottom: 0;
left: 5%;
width: 90%; }
#noty_layout__bottomLeft {
bottom: 20px;
left: 20px;
width: 325px; }
#noty_layout__bottomCenter {
bottom: 5%;
left: 50%;
width: 325px;
-webkit-transform: translate(-webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__bottomRight {
bottom: 20px;
right: 20px;
width: 325px; }
#noty_layout__center {
top: 50%;
left: 50%;
width: 325px;
-webkit-transform: translate(-webkit-calc(-50% - .5px), -webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(calc(-50% - .5px), calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__centerLeft {
top: 50%;
left: 20px;
width: 325px;
-webkit-transform: translate(0, -webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(0, calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__centerRight {
top: 50%;
right: 20px;
width: 325px;
-webkit-transform: translate(0, -webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(0, calc(-50% - .5px)) translateZ(0) scale(1, 1); }
.noty_progressbar {
display: none; }
.noty_has_timeout.noty_has_progressbar .noty_progressbar {
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 3px;
width: 100%;
background-color: #646464;
opacity: 0.2;
filter: alpha(opacity=10); }
.noty_bar {
-webkit-backface-visibility: hidden;
-webkit-transform: translate(0, 0) translateZ(0) scale(1, 1);
-ms-transform: translate(0, 0) scale(1, 1);
transform: translate(0, 0) scale(1, 1);
-webkit-font-smoothing: subpixel-antialiased;
overflow: hidden; }
.noty_effects_open {
opacity: 0;
-webkit-transform: translate(50%);
-ms-transform: translate(50%);
transform: translate(50%);
-webkit-animation: noty_anim_in 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
animation: noty_anim_in 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards; }
.noty_effects_close {
-webkit-animation: noty_anim_out 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
animation: noty_anim_out 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards; }
.noty_fix_effects_height {
-webkit-animation: noty_anim_height 75ms ease-out;
animation: noty_anim_height 75ms ease-out; }
.noty_close_with_click {
cursor: pointer; }
.noty_close_button {
position: absolute;
top: 2px;
right: 2px;
font-weight: bold;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 2px;
cursor: pointer;
-webkit-transition: all .2s ease-out;
transition: all .2s ease-out; }
.noty_close_button:hover {
background-color: rgba(0, 0, 0, 0.1); }
.noty_modal {
position: fixed;
width: 100%;
height: 100%;
background-color: #000;
z-index: 10000;
opacity: .3;
left: 0;
top: 0; }
.noty_modal.noty_modal_open {
opacity: 0;
-webkit-animation: noty_modal_in .3s ease-out;
animation: noty_modal_in .3s ease-out; }
.noty_modal.noty_modal_close {
-webkit-animation: noty_modal_out .3s ease-out;
animation: noty_modal_out .3s ease-out;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards; }
@-webkit-keyframes noty_modal_in {
100% {
opacity: .3; } }
@keyframes noty_modal_in {
100% {
opacity: .3; } }
@-webkit-keyframes noty_modal_out {
100% {
opacity: 0; } }
@keyframes noty_modal_out {
100% {
opacity: 0; } }
@keyframes noty_modal_out {
100% {
opacity: 0; } }
@-webkit-keyframes noty_anim_in {
100% {
-webkit-transform: translate(0);
transform: translate(0);
opacity: 1; } }
@keyframes noty_anim_in {
100% {
-webkit-transform: translate(0);
transform: translate(0);
opacity: 1; } }
@-webkit-keyframes noty_anim_out {
100% {
-webkit-transform: translate(50%);
transform: translate(50%);
opacity: 0; } }
@keyframes noty_anim_out {
100% {
-webkit-transform: translate(50%);
transform: translate(50%);
opacity: 0; } }
@-webkit-keyframes noty_anim_height {
100% {
height: 0; } }
@keyframes noty_anim_height {
100% {
height: 0; } }
.noty_theme__relax.noty_bar {
margin: 4px 0;
overflow: hidden;
border-radius: 2px;
position: relative; }
.noty_theme__relax.noty_bar .noty_body {
padding: 10px; }
.noty_theme__relax.noty_bar .noty_buttons {
border-top: 1px solid #e7e7e7;
padding: 5px 10px; }
.noty_theme__relax.noty_type__alert,
.noty_theme__relax.noty_type__notification {
background-color: #fff;
border: 1px solid #dedede;
color: #444; }
.noty_theme__relax.noty_type__warning {
background-color: #FFEAA8;
border: 1px solid #FFC237;
color: #826200; }
.noty_theme__relax.noty_type__warning .noty_buttons {
border-color: #dfaa30; }
.noty_theme__relax.noty_type__error {
background-color: #FF8181;
border: 1px solid #e25353;
color: #FFF; }
.noty_theme__relax.noty_type__error .noty_buttons {
border-color: darkred; }
.noty_theme__relax.noty_type__info,
.noty_theme__relax.noty_type__information {
background-color: #78C5E7;
border: 1px solid #3badd6;
color: #FFF; }
.noty_theme__relax.noty_type__info .noty_buttons,
.noty_theme__relax.noty_type__information .noty_buttons {
border-color: #0B90C4; }
.noty_theme__relax.noty_type__success {
background-color: #BCF5BC;
border: 1px solid #7cdd77;
color: darkgreen; }
.noty_theme__relax.noty_type__success .noty_buttons {
border-color: #50C24E; }
.noty_theme__metroui.noty_bar {
margin: 4px 0;
overflow: hidden;
position: relative;
box-shadow: rgba(0, 0, 0, 0.298039) 0 0 5px 0; }
.noty_theme__metroui.noty_bar .noty_progressbar {
position: absolute;
left: 0;
bottom: 0;
height: 3px;
width: 100%;
background-color: #000;
opacity: 0.2;
filter: alpha(opacity=20); }
.noty_theme__metroui.noty_bar .noty_body {
padding: 1.25em;
font-size: 14px; }
.noty_theme__metroui.noty_bar .noty_buttons {
padding: 0 10px .5em 10px; }
.noty_theme__metroui.noty_type__alert,
.noty_theme__metroui.noty_type__notification {
background-color: #fff;
color: #1d1d1d; }
.noty_theme__metroui.noty_type__warning {
background-color: #FA6800;
color: #fff; }
.noty_theme__metroui.noty_type__error {
background-color: #CE352C;
color: #FFF; }
.noty_theme__metroui.noty_type__info,
.noty_theme__metroui.noty_type__information {
background-color: #1BA1E2;
color: #FFF; }
.noty_theme__metroui.noty_type__success {
background-color: #60A917;
color: #fff; }
.noty_theme__mint.noty_bar {
margin: 4px 0;
overflow: hidden;
border-radius: 2px;
position: relative; }
.noty_theme__mint.noty_bar .noty_body {
padding: 10px;
font-size: 14px; }
.noty_theme__mint.noty_bar .noty_buttons {
padding: 10px; }
.noty_theme__mint.noty_type__alert,
.noty_theme__mint.noty_type__notification {
background-color: #fff;
border-bottom: 1px solid #D1D1D1;
color: #2F2F2F; }
.noty_theme__mint.noty_type__warning {
background-color: #FFAE42;
border-bottom: 1px solid #E89F3C;
color: #fff; }
.noty_theme__mint.noty_type__error {
background-color: #DE636F;
border-bottom: 1px solid #CA5A65;
color: #fff; }
.noty_theme__mint.noty_type__info,
.noty_theme__mint.noty_type__information {
background-color: #7F7EFF;
border-bottom: 1px solid #7473E8;
color: #fff; }
.noty_theme__mint.noty_type__success {
background-color: #AFC765;
border-bottom: 1px solid #A0B55C;
color: #fff; }
.noty_theme__sunset.noty_bar {
margin: 4px 0;
overflow: hidden;
border-radius: 2px;
position: relative; }
.noty_theme__sunset.noty_bar .noty_body {
padding: 10px;
font-size: 14px;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); }
.noty_theme__sunset.noty_bar .noty_buttons {
padding: 10px; }
.noty_theme__sunset.noty_type__alert,
.noty_theme__sunset.noty_type__notification {
background-color: #073B4C;
color: #fff; }
.noty_theme__sunset.noty_type__alert .noty_progressbar,
.noty_theme__sunset.noty_type__notification .noty_progressbar {
background-color: #fff; }
.noty_theme__sunset.noty_type__warning {
background-color: #FFD166;
color: #fff; }
.noty_theme__sunset.noty_type__error {
background-color: #EF476F;
color: #fff; }
.noty_theme__sunset.noty_type__error .noty_progressbar {
opacity: .4; }
.noty_theme__sunset.noty_type__info,
.noty_theme__sunset.noty_type__information {
background-color: #118AB2;
color: #fff; }
.noty_theme__sunset.noty_type__info .noty_progressbar,
.noty_theme__sunset.noty_type__information .noty_progressbar {
opacity: .6; }
.noty_theme__sunset.noty_type__success {
background-color: #06D6A0;
color: #fff; }
.noty_theme__bootstrap-v3.noty_bar {
margin: 4px 0;
overflow: hidden;
position: relative;
border: 1px solid transparent;
border-radius: 4px; }
.noty_theme__bootstrap-v3.noty_bar .noty_body {
padding: 15px; }
.noty_theme__bootstrap-v3.noty_bar .noty_buttons {
padding: 10px; }
.noty_theme__bootstrap-v3.noty_bar .noty_close_button {
font-size: 21px;
font-weight: 700;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
filter: alpha(opacity=20);
opacity: .2;
background: transparent; }
.noty_theme__bootstrap-v3.noty_bar .noty_close_button:hover {
background: transparent;
text-decoration: none;
cursor: pointer;
filter: alpha(opacity=50);
opacity: .5; }
.noty_theme__bootstrap-v3.noty_type__alert,
.noty_theme__bootstrap-v3.noty_type__notification {
background-color: #fff;
color: inherit; }
.noty_theme__bootstrap-v3.noty_type__warning {
background-color: #fcf8e3;
color: #8a6d3b;
border-color: #faebcc; }
.noty_theme__bootstrap-v3.noty_type__error {
background-color: #f2dede;
color: #a94442;
border-color: #ebccd1; }
.noty_theme__bootstrap-v3.noty_type__info,
.noty_theme__bootstrap-v3.noty_type__information {
background-color: #d9edf7;
color: #31708f;
border-color: #bce8f1; }
.noty_theme__bootstrap-v3.noty_type__success {
background-color: #dff0d8;
color: #3c763d;
border-color: #d6e9c6; }
.noty_theme__bootstrap-v4.noty_bar {
margin: 4px 0;
overflow: hidden;
position: relative;
border: 1px solid transparent;
border-radius: .25rem; }
.noty_theme__bootstrap-v4.noty_bar .noty_body {
padding: .75rem 1.25rem; }
.noty_theme__bootstrap-v4.noty_bar .noty_buttons {
padding: 10px; }
.noty_theme__bootstrap-v4.noty_bar .noty_close_button {
font-size: 1.5rem;
font-weight: 700;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
filter: alpha(opacity=20);
opacity: .5;
background: transparent; }
.noty_theme__bootstrap-v4.noty_bar .noty_close_button:hover {
background: transparent;
text-decoration: none;
cursor: pointer;
filter: alpha(opacity=50);
opacity: .75; }
.noty_theme__bootstrap-v4.noty_type__alert,
.noty_theme__bootstrap-v4.noty_type__notification {
background-color: #fff;
color: inherit; }
.noty_theme__bootstrap-v4.noty_type__warning {
background-color: #fcf8e3;
color: #8a6d3b;
border-color: #faebcc; }
.noty_theme__bootstrap-v4.noty_type__error {
background-color: #f2dede;
color: #a94442;
border-color: #ebccd1; }
.noty_theme__bootstrap-v4.noty_type__info,
.noty_theme__bootstrap-v4.noty_type__information {
background-color: #d9edf7;
color: #31708f;
border-color: #bce8f1; }
.noty_theme__bootstrap-v4.noty_type__success {
background-color: #dff0d8;
color: #3c763d;
border-color: #d6e9c6; }
.noty_theme__semanticui.noty_bar {
margin: 4px 0;
overflow: hidden;
position: relative;
border: 1px solid transparent;
font-size: 1em;
border-radius: .28571429rem;
box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.22) inset, 0 0 0 0 transparent; }
.noty_theme__semanticui.noty_bar .noty_body {
padding: 1em 1.5em;
line-height: 1.4285em; }
.noty_theme__semanticui.noty_bar .noty_buttons {
padding: 10px; }
.noty_theme__semanticui.noty_type__alert,
.noty_theme__semanticui.noty_type__notification {
background-color: #f8f8f9;
color: rgba(0, 0, 0, 0.87); }
.noty_theme__semanticui.noty_type__warning {
background-color: #fffaf3;
color: #573a08;
box-shadow: 0 0 0 1px #c9ba9b inset, 0 0 0 0 transparent; }
.noty_theme__semanticui.noty_type__error {
background-color: #fff6f6;
color: #9f3a38;
box-shadow: 0 0 0 1px #e0b4b4 inset, 0 0 0 0 transparent; }
.noty_theme__semanticui.noty_type__info,
.noty_theme__semanticui.noty_type__information {
background-color: #f8ffff;
color: #276f86;
box-shadow: 0 0 0 1px #a9d5de inset, 0 0 0 0 transparent; }
.noty_theme__semanticui.noty_type__success {
background-color: #fcfff5;
color: #2c662d;
box-shadow: 0 0 0 1px #a3c293 inset, 0 0 0 0 transparent; }
.noty_theme__nest.noty_bar {
margin: 0 0 15px 0;
overflow: hidden;
border-radius: 2px;
position: relative;
box-shadow: rgba(0, 0, 0, 0.098039) 5px 4px 10px 0; }
.noty_theme__nest.noty_bar .noty_body {
padding: 10px;
font-size: 14px;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); }
.noty_theme__nest.noty_bar .noty_buttons {
padding: 10px; }
.noty_layout .noty_theme__nest.noty_bar {
z-index: 5; }
.noty_layout .noty_theme__nest.noty_bar:nth-child(2) {
position: absolute;
top: 0;
margin-top: 4px;
margin-right: -4px;
margin-left: 4px;
z-index: 4;
width: 100%; }
.noty_layout .noty_theme__nest.noty_bar:nth-child(3) {
position: absolute;
top: 0;
margin-top: 8px;
margin-right: -8px;
margin-left: 8px;
z-index: 3;
width: 100%; }
.noty_layout .noty_theme__nest.noty_bar:nth-child(4) {
position: absolute;
top: 0;
margin-top: 12px;
margin-right: -12px;
margin-left: 12px;
z-index: 2;
width: 100%; }
.noty_layout .noty_theme__nest.noty_bar:nth-child(5) {
position: absolute;
top: 0;
margin-top: 16px;
margin-right: -16px;
margin-left: 16px;
z-index: 1;
width: 100%; }
.noty_layout .noty_theme__nest.noty_bar:nth-child(n+6) {
position: absolute;
top: 0;
margin-top: 20px;
margin-right: -20px;
margin-left: 20px;
z-index: -1;
width: 100%; }
#noty_layout__bottomLeft .noty_theme__nest.noty_bar:nth-child(2),
#noty_layout__topLeft .noty_theme__nest.noty_bar:nth-child(2) {
margin-top: 4px;
margin-left: -4px;
margin-right: 4px; }
#noty_layout__bottomLeft .noty_theme__nest.noty_bar:nth-child(3),
#noty_layout__topLeft .noty_theme__nest.noty_bar:nth-child(3) {
margin-top: 8px;
margin-left: -8px;
margin-right: 8px; }
#noty_layout__bottomLeft .noty_theme__nest.noty_bar:nth-child(4),
#noty_layout__topLeft .noty_theme__nest.noty_bar:nth-child(4) {
margin-top: 12px;
margin-left: -12px;
margin-right: 12px; }
#noty_layout__bottomLeft .noty_theme__nest.noty_bar:nth-child(5),
#noty_layout__topLeft .noty_theme__nest.noty_bar:nth-child(5) {
margin-top: 16px;
margin-left: -16px;
margin-right: 16px; }
#noty_layout__bottomLeft .noty_theme__nest.noty_bar:nth-child(n+6),
#noty_layout__topLeft .noty_theme__nest.noty_bar:nth-child(n+6) {
margin-top: 20px;
margin-left: -20px;
margin-right: 20px; }
.noty_theme__nest.noty_type__alert,
.noty_theme__nest.noty_type__notification {
background-color: #073B4C;
color: #fff; }
.noty_theme__nest.noty_type__alert .noty_progressbar,
.noty_theme__nest.noty_type__notification .noty_progressbar {
background-color: #fff; }
.noty_theme__nest.noty_type__warning {
background-color: #FFD166;
color: #fff; }
.noty_theme__nest.noty_type__error {
background-color: #EF476F;
color: #fff; }
.noty_theme__nest.noty_type__error .noty_progressbar {
opacity: .4; }
.noty_theme__nest.noty_type__info,
.noty_theme__nest.noty_type__information {
background-color: #118AB2;
color: #fff; }
.noty_theme__nest.noty_type__info .noty_progressbar,
.noty_theme__nest.noty_type__information .noty_progressbar {
opacity: .6; }
.noty_theme__nest.noty_type__success {
background-color: #06D6A0;
color: #fff; }
.noty_theme__light.noty_bar {
margin: 4px 0;
overflow: hidden;
border-radius: 2px;
position: relative; }
.noty_theme__light.noty_bar .noty_body {
padding: 10px; }
.noty_theme__light.noty_bar .noty_buttons {
border-top: 1px solid #e7e7e7;
padding: 5px 10px; }
.noty_theme__light.noty_type__alert,
.noty_theme__light.noty_type__notification {
background-color: #fff;
border: 1px solid #dedede;
color: #444; }
.noty_theme__light.noty_type__warning {
background-color: #FFEAA8;
border: 1px solid #FFC237;
color: #826200; }
.noty_theme__light.noty_type__warning .noty_buttons {
border-color: #dfaa30; }
.noty_theme__light.noty_type__error {
background-color: #ED7000;
border: 1px solid #e25353;
color: #FFF; }
.noty_theme__light.noty_type__error .noty_buttons {
border-color: darkred; }
.noty_theme__light.noty_type__info,
.noty_theme__light.noty_type__information {
background-color: #78C5E7;
border: 1px solid #3badd6;
color: #FFF; }
.noty_theme__light.noty_type__info .noty_buttons,
.noty_theme__light.noty_type__information .noty_buttons {
border-color: #0B90C4; }
.noty_theme__light.noty_type__success {
background-color: #57C880;
border: 1px solid #7cdd77;
color: darkgreen; }
.noty_theme__light.noty_type__success .noty_buttons {
border-color: #50C24E; }
/*# sourceMappingURL=noty.css.map*/

View File

@@ -83,12 +83,18 @@
1. 你的IP地址会被记录在Nginx的日志中。在面临攻击、爬虫等恶意行为时我会找到这个IP然后加到防火墙中。我不会公开或与第三方分享访问日志<br>
2. 我使用了Google Analytics请参考Google Analytics的隐私政策<br>
3. 我使用了Cloudflare请参考Cloudflare的隐私政策。<br>
3. 我记录了metrics信息用于优化日后访问量此信息不包含个人信息无法用于追踪你。可以<a href="/api/metrics">点击这里查看</a>
4. 我记录了metrics信息用于优化日后访问量此信息不包含个人信息无法用于追踪你。可以<a href="/api/metrics">点击这里查看</a>
5. 如果你选择注册我会保存你的用户名、加密后的密码、注册时间、UA等信息。此类信息不会被公开或与第三方分享。
<h2>16. 数据库下载不了呀!</h2>
那你试试这几个呢?
<a href="/data/yyets_mongo.gz">MongoDB</a> 实时更新无checksum<br>
<a href="/data/yyets_mysql.zip">MySQL 5.7</a> aeee83e54e5de37df9392ab4f01eb9c43437f47d<br>
<a href="/data/yyets_sqlite.zip">SQLite</a> 13a4635c6bd41b605a92d33a496bc563f5772652<br>
<h2>17. 注册需要提供什么?</h2>
呃,其实随便写个用户名密码就可以了,没有限制的哦。我使用了 pbkdf2_sha256 安全保存你的密码。
我知道这个功能太简陋了,比如说无法找回密码,很多很多。凑合用吧😂
哦对了,你的用户信息不会被包含在上述数据库之中。
<br>
<br>
<button><a href="/">返回主页</a></button>

View File

@@ -101,6 +101,8 @@
color: green;
}
</style>
</head>
<body>
<div class="centered">
@@ -142,9 +144,21 @@
我的博客 <a class="footer" href="https://dmesg.app/">土豆不好吃</a>
</h3>
</div>
<form method="post" style="display: none" id="login-form">
<label>
<input type="text" required="required" placeholder="用户名" name="username"/>
</label>
<label>
<input type="password" required="required" placeholder="密码" name="password"/>
</label>
<button class="but" type="submit" onclick="login()">登录</button>
</form>
</body>
<script src="js/axios.min.js"></script>
<script src="js/analytics.js"></script>
<script src="js/common.js"></script>
<link href="css/noty.css" rel="stylesheet">
<script src="js/noty.min.js"></script>
<script>
accessMetrics("access");
@@ -152,9 +166,7 @@
// get top
axios.get('/api/top')
.then(function (response) {
// handle success
showTop(response.data)
// console.log(response.data);
})
.catch(function (error) {
// handle error
@@ -197,11 +209,52 @@
divChild.innerHTML = html;
divChild = divChild.firstChild;
divParent.appendChild(divChild);
}
}
document.getElementsByClassName("tab")[0].firstElementChild.className += " active"
document.getElementById("ALL").style.display = "block"
let like = document.getElementById("LIKE");
let user_cookie = getCookie("username");
let login_form = document.getElementById("login-form");
if (user_cookie === "") {
like.innerHTML = "请登录,未注册用户将会自动注册<br><br>" + login_form.innerHTML + "<br>"
}
}
function login() {
let username = document.getElementsByName("username")[0].value
let password = document.getElementsByName("password")[0].value
axios.post('/api/user', {
username: username,
password: password
})
.then(function (response) {
let message = response.status === 201 ? "注册成功" : "登录成功"
new Noty({
type: 'success',
layout: 'topRight',
theme: 'relax',
text: message,
timeout: 1500
}).show();
setTimeout(function () {
location.reload();
}, 3000);
})
.catch(function (error) {
new Noty({
type: 'error',
layout: 'topRight',
theme: 'relax',
text: error.response.data,
timeout: 1500
}).show();
});
}
@@ -216,7 +269,6 @@
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(cityName).style.display = "block";
console.log(evt)
evt.currentTarget.className += " active";
}

9
web/js/analytics.js vendored
View File

@@ -1,9 +0,0 @@
function accessMetrics(type) {
axios.post('/api/metrics?type=' + type)
.then(function (response) {
// console.log(response);
})
.catch(function (error) {
// console.log(error);
});
}

21
web/js/common.js Normal file
View File

@@ -0,0 +1,21 @@
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
function accessMetrics(type) {
axios.post('/api/metrics?type=' + type)
.then(function (response) {
// console.log(response);
})
.catch(function (error) {
// console.log(error);
});
}

17
web/js/noty.min.js vendored Normal file

File diff suppressed because one or more lines are too long

46
web/resource.html vendored
View File

@@ -204,7 +204,8 @@
<div class="ui-limit">
<div class="logo-wrapper">
<div class="logo"></div>
<div class="desc">资源分享站</div>
<div class="desc"><a href="/">资源分享站</a>
</div>
</div>
<div class="btn-group" role="group" aria-label="...">
@@ -214,7 +215,7 @@
<div class="view-count">
<span class="desc"><i class="fa fa-home"></i><a href="index.html">返回首页</a> </span> &nbsp;
<span class="desc"><i class="fa fa-heart"></i><a id="fav" onclick="addFav()">添加收藏</a> </span> &nbsp;
<span class="desc"><i class="fa fa-eye"></i>访问量:</span>
<span class="count">{{ info.views }}</span>
</div>
@@ -683,6 +684,10 @@
alert("发生错误!请清除浏览器缓存后重试")
}
var data = json.data;
// like button
let fav = document.getElementById("fav");
fav.innerHTML = json.is_like ? "取消收藏" : "添加收藏"
document.title = data.info.cnname + " " + data.info.enname;
var list = data.list;
//me.addSupprtTip(data.ad_rate)
@@ -874,8 +879,41 @@
</script>
<script src="js/axios.min.js"></script>
<script src="js/analytics.js"></script>
<script> accessMetrics("resource");
<link href="css/noty.css" rel="stylesheet">
<script src="js/noty.min.js"></script>
<script src="js/common.js"></script>
<script>
accessMetrics("resource");
function addFav() {
let resource_id = document.URL.split("id=")[1];
axios.patch('/api/user', {
resource_id: resource_id,
}).then(function (response) {
new Noty({
type: 'success',
layout: 'topRight',
theme: 'relax',
text: response.data,
timeout: 1500
}).show();
// change text to un fav
let fav = document.getElementById("fav")
fav.innerHTML = fav.innerHTML === "取消收藏" ? "添加收藏" : "取消收藏"
}).catch(function (error) {
new Noty({
type: 'error',
layout: 'topRight',
theme: 'relax',
text: "发生错误 " + error.response.data,
timeout: 1500
}).show();
});
}
</script>
</body>
</html>

View File

@@ -82,7 +82,7 @@
</div>
</body>
<script src="js/axios.min.js"></script>
<script src="js/analytics.js"></script>
<script src="js/common.js"></script>
<script>
let kwe = document.URL.split("kw=")[1];

View File

@@ -14,6 +14,8 @@ import json
import time
from datetime import date, timedelta
from passlib.hash import pbkdf2_sha256
import redis
import pymongo
from http import HTTPStatus
@@ -135,6 +137,80 @@ class IndexHandler(BaseHandler):
self.write(resp)
class UserHandler(BaseHandler):
executor = ThreadPoolExecutor(10)
def set_login(self, username):
self.set_secure_cookie("username", username)
@run_on_executor()
def login_user(self):
data = json.loads(self.request.body)
username = data["username"]
password = data["password"]
data = self.mongo.db["users"].find_one({"username": username})
returned_value = ""
if data:
# try to login
stored_password = data["password"]
if pbkdf2_sha256.verify(password, stored_password):
self.set_status(HTTPStatus.OK)
self.set_login(username)
else:
self.set_status(HTTPStatus.FORBIDDEN)
returned_value = "用户名或密码错误"
else:
hash_value = pbkdf2_sha256.hash(password)
try:
self.mongo.db["users"].insert_one(dict(username=username, password=hash_value,
date=time.asctime(),
ip=self.request.remote_ip,
browser=self.request.headers['user-agent']
)
)
self.set_login(username)
self.set_status(HTTPStatus.CREATED)
except Exception as e:
self.set_status(HTTPStatus.INTERNAL_SERVER_ERROR)
returned_value = str(e)
return returned_value
@run_on_executor()
def add_remove_fav(self):
data = json.loads(self.request.body)
resource_id = int(data["resource_id"])
username = self.get_secure_cookie("username")
if username:
username = username.decode('u8')
like_list: list = self.mongo.db["users"].find_one({"username": username}).get("like", [])
if resource_id in like_list:
returned_value = "已取消收藏"
like_list.remove(resource_id)
else:
self.set_status(HTTPStatus.CREATED)
like_list.append(resource_id)
returned_value = "已添加收藏"
value = dict(like=like_list)
self.mongo.db["users"].update_one({"username": username}, {'$set': value})
else:
returned_value = "请先登录"
self.set_status(HTTPStatus.UNAUTHORIZED)
return returned_value
@gen.coroutine
def post(self):
resp = yield self.login_user()
self.write(resp)
@gen.coroutine
def patch(self):
resp = yield self.add_remove_fav()
self.write(resp)
class ResourceHandler(BaseHandler):
executor = ThreadPoolExecutor(100)
@@ -168,7 +244,15 @@ class ResourceHandler(BaseHandler):
if forbidden:
self.set_status(HTTPStatus.FORBIDDEN)
# is fav?
username = self.get_secure_cookie("username")
if username:
username = username.decode('u8')
user_like_data = self.mongo.db["users"].find_one({"username": username})
if user_like_data and param in user_like_data.get("like", []):
data["is_like"] = True
else:
data["is_like"] = False
return data
@run_on_executor()
@@ -201,21 +285,32 @@ class ResourceHandler(BaseHandler):
class TopHandler(BaseHandler):
executor = ThreadPoolExecutor(100)
projection = {'_id': False, 'data.info': True}
def get_user_like(self) -> list:
username = self.get_secure_cookie("username")
if username:
like_list = self.mongo.db["users"].find_one({"username": username.decode('u8')}).get("like", [])
data = self.mongo.db["yyets"].find({"data.info.id": {"$in": like_list}}, self.projection) \
.sort("data.info.views", pymongo.DESCENDING)
return list(data)
return []
@run_on_executor()
def get_top_resource(self):
projection = {'_id': False,
'data.info': True,
}
area_dict = dict(ALL={"$regex": ".*"}, US="美国", JP="日本", KR="韩国", UK="英国")
all_data = {}
for abbr, area in area_dict.items():
data = self.mongo.db["yyets"].find({"data.info.area": area}, projection).sort("data.info.views",
pymongo.DESCENDING).limit(15)
data = self.mongo.db["yyets"].find({"data.info.area": area}, self.projection). \
sort("data.info.views", pymongo.DESCENDING).limit(15)
all_data[abbr] = list(data)
area_dict["ALL"] = "全部"
area_dict["LIKE"] = "收藏"
all_data["LIKE"] = self.get_user_like()
all_data["class"] = area_dict
return all_data
@@ -397,6 +492,7 @@ class RunServer:
handlers = [
(r'/api/resource', ResourceHandler),
(r'/api/top', TopHandler),
(r'/api/user', UserHandler),
(r'/api/name', NameHandler),
(r'/api/metrics', MetricsHandler),
(r'/api/grafana/', GrafanaIndexHandler),
@@ -407,8 +503,12 @@ class RunServer:
(r'/(.*\.html|.*\.js|.*\.css|.*\.png|.*\.jpg|.*\.ico|.*\.gif|.*\.woff2|.*\.gz|.*\.zip)', web.StaticFileHandler,
{'path': static_path}),
]
settings = {
"cookie_secret": "eo2kcgpKwXj8Q3PKYj6nIL1J4j3b58DX"
}
application = web.Application(handlers, xheaders=True, default_handler_class=NotFoundHandler)
application = web.Application(handlers, xheaders=True, default_handler_class=NotFoundHandler,
**settings)
@staticmethod
def run_server(port, host, **kwargs):