add douban, add sponsor link

This commit is contained in:
BennyThink
2021-07-10 23:28:44 +08:00
parent eba2959d4d
commit f7b72aa769
12 changed files with 4547 additions and 5 deletions

1
.gitattributes vendored
View File

@@ -16,3 +16,4 @@ yyetsweb/resource.html linguist-vendored
yyetsweb/js/common.js -linguist-vendored
tests/data/* linguist-vendored
yyetsweb/craw_data/*.html linguist-vendored

27
API.md
View File

@@ -13,7 +13,7 @@
- [x] 联合搜索字幕侠、new字幕组、追新番
- [x] grafana面板
- [ ] 豆瓣接口
- [ ] 豆瓣接口:进行中……
- [ ] 用户体系(添加邮箱,邮件支持,找回密码)
- [ ] 评论通知,需要新接口
- [ ] 添加资源API
@@ -557,3 +557,28 @@
"count": 1
}
```
# 豆瓣
## 获取简介等信息
* GET `/api/douban?resource_id=34812`
第一次请求会比较慢
```json
{
"douban_id": "26816519",
"douban_link": "https://movie.douban.com/subject/26816519/",
"poster_link": "https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2400201631.jpg",
"resource_id": 34812,
"rating": "8.4",
"actors": "新垣结衣 / 星野源 / 大谷亮平 / 藤井隆 / 真野惠里菜 / 成田凌 / 山贺琴子 / 宇梶刚士 / 富田靖子 / 古田新太 / 石田百合子 / 细田善彦 / 古馆宽治 / 叶山奖之",
"year": "2016",
"introduction": "森山实栗(新垣结衣饰)自研究生毕业之后就一直仕途不顺,最近更是惨遭解雇,处于“无业游民”的状态之下,日子过得十分凄惨。经由父亲的介绍,无处可去的实栗来到了名为津崎平匡(星野源饰)的单身男子家中,为其料理家事,就这样,二十五岁的实栗成为了一名家政妇。实栗心地善良手脚勤快,在她的安排和劳作下,平匡家中的一切被打理的井井有条,实栗因此获得了平匡的信赖,亦找到了生活的重心,重新振作了起来。然而好景不长,实栗的父母决定搬离此地,这也就意味着实栗必须“离职”。实在无法接受此事的实栗决定和平匡“契约结婚”,在外装做夫妻,在内依旧是雇主和职员。就这样,这对“孤男寡女”开始了他们的同居生活。"
}
```
## 获取海报
* GET `api/douban?resource_id=34812&type=image`
会返回相应格式jpeg、webp、png等的图片与上次数据中 `poster_link`所看到的内容相同

View File

@@ -103,7 +103,7 @@ yyets_offline - 人人影视离线数据
* 捐助我,[爱发电?](https://afdian.net/@BennyThink)
# 感谢
感谢所有支持本项目的人!
感谢所有[支持本项目](SPONSOR.md)的人!
# License
[MIT](LICENSE)

5
SPONSOR.md Normal file
View File

@@ -0,0 +1,5 @@
感谢如下支持本项目的小可爱们!
**如果你也想把你的名字和链接加到这里,请和我私聊确认哦~否则我就不知道怎么写啦**
* [KnowsCount](https://github.com/KnowsCount)

View File

@@ -11,5 +11,5 @@ captcha==0.3
passlib==1.7.4
fakeredis==1.5.0
pytz==2021.1
filetype==1.0.7
requests[socks]

View File

@@ -15,12 +15,16 @@ import time
from http import HTTPStatus
from datetime import timedelta, date
from bson.objectid import ObjectId
from urllib.parse import unquote
import re
import logging
from bs4 import BeautifulSoup
import requests
from passlib.handlers.pbkdf2 import pbkdf2_sha256
from database import (AnnouncementResource, BlacklistResource, CommentResource, ResourceResource,
GrafanaQueryResource, MetricsResource, NameResource, OtherResource,
GrafanaQueryResource, MetricsResource, NameResource, OtherResource, DoubanResource,
TopResource, UserLikeResource, UserResource, CaptchaResource, Redis, CommentChildResource)
from utils import ts_date
@@ -29,6 +33,8 @@ sys.path.append(lib_path)
from fansub import ZhuixinfanOnline, ZimuxiaOnline, NewzmzOnline, CK180Online
mongo_host = os.getenv("mongo") or "localhost"
DOUBAN_SEARCH = "https://www.douban.com/search?cat=1002&q={}"
DOUBAN_DETAIL = "https://movie.douban.com/subject/{}/"
class Mongo:
@@ -479,3 +485,73 @@ class UserMongoResource(UserResource, Mongo):
self.db["users"].update_one({"username": username},
{"$set": {"lastDate": (ts_date()), "lastIP": now_ip}}
)
class DoubanMongoResource(DoubanResource, Mongo):
def get_douban_data(self, rid: int) -> dict:
return self.find_douban(rid)
def get_douban_image(self, rid: int) -> bytes:
db_data = self.get_douban_data(rid)
return db_data["poster_data"]
def find_douban(self, resource_id: int):
session = requests.Session()
ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
session.headers.update({"User-Agent": ua})
douban_col = self.db["douban"]
yyets_col = self.db["yyets"]
data = douban_col.find_one({"resource_id": resource_id}, {"_id": False})
if data:
logging.info("Existing data for %s", resource_id)
return data
projection = {"data.info.cnname": True, "data.info.enname": True, "data.info.aliasname": True}
names = yyets_col.find_one({"data.info.id": resource_id}, projection=projection)
if names is None:
return {}
cname = names["data"]["info"]["cnname"]
logging.info("cnname for douban is %s", cname)
# enname = names["data"]["info"]["enname"]
# aliasname = names["data"]["info"]["aliasname"].split("/")
search_html = session.get(DOUBAN_SEARCH.format(cname)).text
logging.info("Analysis search html...%s", search_html)
soup = BeautifulSoup(search_html, 'html.parser')
douban_item = soup.find_all("div", class_="content")
fwd_link = unquote(douban_item[0].a["href"])
douban_id = re.findall(r"https://movie.douban.com/subject/(\d*)/&query=", fwd_link)[0]
detail_link = DOUBAN_DETAIL.format(douban_id)
detail_html = session.get(detail_link).text
logging.info("Analysis detail html...%s", detail_link)
soup = BeautifulSoup(detail_html, 'html.parser')
poster = soup.find_all("div", id="mainpic")
poster_image_link = poster[0].a.img["src"]
rating_obj = soup.find_all("strong", class_="ll rating_num")
rating = rating_obj[0].text
actors_obj = soup.find_all("span", class_="attrs")
actors = actors_obj[-1].text
year = soup.find_all("span", class_="year")[0].text
year_text = re.sub(r"[()]", "", year)
intro = soup.find_all("span", property="v:summary")[0].text
intro = re.sub(r"\s", "", intro)
final_data = {
"douban_id": douban_id,
"douban_link": detail_link,
"poster_link": poster_image_link,
"poster_data": session.get(poster_image_link).content,
"resource_id": resource_id,
"rating": rating,
"actors": actors,
"year": year_text,
"introduction": intro
}
douban_col.insert_one(final_data.copy())
return final_data

View File

@@ -0,0 +1,20 @@
#!/usr/local/bin/python3
# coding: utf-8
# YYeTsBot - douban.py
# 7/10/21 22:59
#
__author__ = "Benny <benny.think@gmail.com>"
from bs4 import BeautifulSoup
import re
with open("douban_detail.html") as f:
detail_html = f.read()
soup = BeautifulSoup(detail_html, 'html.parser')
intro = soup.find_all("span", property="v:summary")[0].text
i = re.sub(r"\s", "", intro)
print(i)

3733
yyetsweb/craw_data/douban_detail.html vendored Normal file

File diff suppressed because it is too large Load Diff

642
yyetsweb/craw_data/douban_search.html vendored Normal file
View File

@@ -0,0 +1,642 @@
<!DOCTYPE html>
<html lang="zh-CN" class="ua-linux ua-webkit">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="renderer" content="webkit">
<meta name="referrer" content="always">
<meta name="google-site-verification" content="ok0wCgT20tBBgo9_zat2iAcimtN4Ftf5ccsh092Xeyw" />
<title>
搜索: 逃避可耻却有用
</title>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="Sun, 6 Mar 2005 01:00:00 GMT">
<link rel="search" type="application/opensearchdescription+xml" title="豆瓣搜索" href="/opensearch">
<script >var _head_start = new Date();</script>
<script src="https://img3.doubanio.com/f/shire/72ced6df41d4d158420cebdd254f9562942464e3/js/jquery.min.js"></script>
<script src="https://img3.doubanio.com/f/shire/22ee83f45f94c7a90e73e0ee4acd18f902a6991f/js/douban.js"></script>
<link href="https://img3.doubanio.com/f/shire/6522c42d2aba9757aeefa0c35cc0cefc9229747c/css/douban.css" rel="stylesheet" type="text/css">
<style type="text/css">
h1{display:none}.mod-search{position:relative;overflow:hidden;zoom:1;margin-bottom:28px;background-color:#f7f7f8;padding:7px}.mod-search input{-webkit-appearance:none;border:0;background:transparent}.mod-search label{position:absolute;left:12px;top:10px;line-height:30px;cursor:text;color:#bbb}.mod-search legend{display:none}.mod-search fieldset{border:0;padding:0;margin:0}.mod-search .inp{height:30px;cursor:text;border:1px solid #dcdcdc;background-color:#fff}.mod-search .inp input{background:#fff;width:94%;margin:0;text-align:left;height:30px;padding-left:6px;height:28px\9;line-height:28px\9;outline:0}.mod-search .inp-btn{position:absolute;top:6px;right:6px;width:30px;height:30px;zoom:1;overflow:hidden}.mod-search .inp-btn input{width:100%;height:100%;font-size:0;padding:35px 0 0 0;overflow:hidden;background:url(https://img3.doubanio.com/f/sns/f71f15922ebd7c0ff0ea0e7a25577529efd8981a/pics/icon/bn_srh_1.png) no-repeat 45% 45%;color:transparent;cursor:pointer}.search-cate{float:left;margin-right:35px;width:65px;font-size:0}.search-cate li{width:65px;display:inline-block;*display:inline;zoom:1;margin-bottom:12px;line-height:1.2;font-size:12px}.search-cate li a{display:block;padding:3px 0;text-align:center}.search-cate li a:link,.search-cate li a:visited{color:#111}.search-cate li a:hover{color:#fff;background-color:#8cd379;border-radius:3px}.search-cate .on a:link,.search-cate .on a:visited,.search-cate .on a:hover,.search-cate .on a:active{background:#7fc06e;color:#fff;border-radius:3px}.search-cate .new a{background:url(https://img3.doubanio.com/f/sns/e49eca1517424a941871a2667a8957fd6c72d632/pics/new_menu.gif) no-repeat right 0}.search-result{overflow:hidden;zoom:1}.search-result .no-result{font-size:12px}.no-result{margin-bottom:40px;font-size:14px;color:#999}.frm-find{margin-bottom:30px}.frm-find .item{position:relative;margin-bottom:10px;color:#666}.frm-find .item label{position:absolute;top:2px;left:2px;line-height:20px;color:#999;cursor:text}.frm-find .item input{padding:5px;border:1px solid #ccc}.frm-find .item-accounts{border:1px solid #ccc}.frm-find .item-accounts input{width:60%;border:0}.frm-find .item-accounts .mail-domain{position:absolute;top:0;right:2px}.frm-find .item-accounts .mail-domain select{padding:2px;border:0;font-size:13px;background:transparent;-webkit-appearance:none}.frm-find .item-password input{width:98%}.result .ic-movie-mark{background-color:#71b5de}.result .ic-read-mark{background-color:#825d5b}
.search_report { float:right; margin-top:15px; margin-right:10px;}
.search_report a:link,
.search_report a:hover,
.search_report a:visited,
.search_report a:active { color:#bbb; }
.search_report a:hover { color:#fff; background-color:#bbb; }
.search-list-item a{color:#666}
.search-list-item a:hover{color:#fff}
.topic-promotion {font-size: 13px; border-bottom: 1px dashed #CCC; padding-bottom: 15px; margin-bottom: 10px}
.topic-promotion a:hover {color: #37A; background-color: #E8E8E8}
.topic-promotion a {display: inline-block; padding: 3px 23px; margin-right: 10px; background: #F5F5F5}
.topic-promotion a.new-icon {background: #F5F5F5 url('https://img3.doubanio.com/f/shire/e49eca1517424a941871a2667a8957fd6c72d632/pics/new_menu.gif') no-repeat right 0}
.topic-promotion span {font-size: 12px; color: gray}
.topic-promotion .related-topics {margin-top: 20px}
.result > .pic {position: relative;}
.user-verify-icon {
display: block;
background: url('https://img3.doubanio.com/f/shire/8cff6c7f0bfa5a9dbe604b51f4de62f655c233ce/pics/ic_verify@2x.png') no-repeat center;
background-size: contain;
border-radius: 50%;
width: 20px;
height: 20px;
position: absolute;
right: -4px;
bottom: -4px;
}
</style>
<link rel="stylesheet" href="https://img3.doubanio.com/misc/mixed_static/6078d5bcd65d3c51.css">
<script>
var o={},PEOPLE_ID="",currTagId="",totallen=16,newGroupNum=0,groupNameArr=[],isDuplicate=!1,mlist=$(".menu-list"),olist=$(".group-opts-list"),sglist=$(".set-group-list"),sgarrow=$(".user-group-arrow"),addGroup=$("#add-new-group"),TEMPL_NEW_TAG='<li><a href="?tag={ID}">{NAME}</a></li>',TEMPL_MENU_LIST='<li><a href="?tag=0">全部</a></li>{CUSTOM_TAGS}<li class="last"><a href="?tag=2">未分组</a></li>',TEMPL_NEW_GROUP_ITEM='<li><input type="checkbox" id="{GID}" value="{GID}" {CHECKED}><label for="{GID}">{GNAME}</label></li>',TEMPL_SET_LIST_ITEMS='{CUSTOM_ITEMS}<li class="last"><span class="create-new">新分组</span></li>',TEMPL_GROUP_OPTS='<ul class="group-opts-list"><li id="del-group">删除分组</li><li id="rename-group">改组名</li></ul>',TEMPL_FRIEND_TIPS='<span class="tips">(可看仅朋友可见内容)</span>',TEMPL_EDIT_ICON='&nbsp;<em class="icon-edit"></em>',TEMPL_TIPS='<span class="tips tlimit">{TIPS}</span>',CSS_LAST_ITEM=".set-group-list .last",CSS_INPUT_CREATE=".input-create",CSS_ARROW_SELECT="arrow-select",CSS_LOADER=".gray-loader",CSS_SET_GROUP_LIST=".set-group-list",CSS_EM_TIPS=".tlimit",TXT_DUP_NAME="已有同名分组",TXT_NULL_NAME="请输入分组名",TXT_BAN_WORDS="分组名称含有被禁止的内容",isIE6=!(!$.browser.msie||"6.0"!==$.browser.version),collectGroupName=function(){var e=$("#db-timeline-hd a").toArray();$.each(e,function(e,t){groupNameArr[e]=$.trim($(t).text())})},countNum=function(){var e=$("input[type=checkbox]:checked").length;e>0?$(".sel-wrapper .user-rs").html("加入"+e+"个分组"):$(".sel-wrapper .user-rs").html("加入分组")},changeGroupShow=function(e){var t=e.parents(".user-group-arrow").prev(".user-rs"),a=e.closest(CSS_SET_GROUP_LIST).children().children(":checked"),r=a.length,_=a.toArray(),l=$.map(_,function(e){return $(e).next().text().escapeHTML()});r>0?(t.html(l.join(", ").substring(0,totallen)).show(),l.join(", ").length>=totallen&&t.append("...")):t.text("未分组")},createNewGroup=function(e,t,a,r){$.each(groupNameArr,function(t,r){return a===r||"全部"===a||"未分组"===a?(isDuplicate=!0,$(CSS_EM_TIPS,e).length?$(CSS_EM_TIPS,e).text(TXT_DUP_NAME):$(CSS_INPUT_CREATE,e).after(TEMPL_TIPS.replace("{TIPS}",TXT_DUP_NAME)),!1):void(isDuplicate=!1)}),a&&!isDuplicate?($(CSS_EM_TIPS).remove(),$.post_withck("/j/contact/newtag",{name:a,people:t},function(t){if(t.result){var a=[],_=[],l="",T="",S="",n=t.data.newtag.id,i=t.data.newtag.name;mlist.length&&($.each(t.data.all,function(e,t){a[e]=TEMPL_NEW_TAG.replace("{ID}",t.id).replace("{NAME}",t.name.escapeHTML())}),mlist.html(TEMPL_MENU_LIST.replace("{CUSTOM_TAGS}",a.join(""))),l=$(".menu-list a:contains("+currGroupName+")"),l.parent().addClass("on"),"全部"!==currGroupName&&"朋友"!==currGroupName&&"未分组"!==currGroupName&&l.append(TEMPL_EDIT_ICON).after(TEMPL_GROUP_OPTS)),$.each(t.data.all,function(e,t){_[e]=TEMPL_NEW_GROUP_ITEM.replace(/{GID}/g,t.id).replace("{GNAME}",t.name.escapeHTML()).replace("{CHECKED}",t.status?'checked="checked"':"")}),$(CSS_SET_GROUP_LIST,e).html(TEMPL_SET_LIST_ITEMS.replace("{CUSTOM_ITEMS}",_.join(""))),$(CSS_SET_GROUP_LIST+" li:first",e).append(TEMPL_FRIEND_TIPS),$(CSS_SET_GROUP_LIST).length>1&&(S=$("#"+n).parent().next().children("label").text()||"",T=TEMPL_NEW_GROUP_ITEM.replace(/{GID}/g,n).replace(/{GNAME}/g,i.escapeHTML()).replace("{CHECKED}",""),S?$(CSS_SET_GROUP_LIST+' li:contains("'+S+'")').before(T):$(CSS_LAST_ITEM).before(T),$(CSS_SET_GROUP_LIST+" input[id="+n+"]",e).eq(1).parent().remove()),newGroupNum=$(CSS_SET_GROUP_LIST+" input[type=checkbox]",e).length,newGroupNum>=r&&$(CSS_LAST_ITEM).remove();var s=$(e).children().children("li:first");$(".custom-popwin").length?countNum(s):changeGroupShow(s),collectGroupName()}else"ban"===t.msg&&($(CSS_EM_TIPS,e).length?$(CSS_EM_TIPS,e).text(TXT_BAN_WORDS):$(CSS_INPUT_CREATE,e).after(TEMPL_TIPS.replace("{TIPS}",TXT_BAN_WORDS)))},"json")):a||($(CSS_EM_TIPS,e).length?$(CSS_EM_TIPS,e).text(TXT_NULL_NAME):$(CSS_INPUT_CREATE,e).after(TEMPL_TIPS.replace("{TIPS}",TXT_NULL_NAME)))};collectGroupName(),isIE6&&$(CSS_SET_GROUP_LIST+' li:not(".last")').hover(function(){$(this).addClass("hover")},function(){$(this).removeClass("hover")});
</script>
<!-- Google Adsense Search AD begin -->
<script async="async" src="https://www.google.com/adsense/search/ads.js"></script>
<script type="text/javascript" charset="utf-8">
(function(g,o){g[o]=g[o]||function(){(g[o]['q']=g[o]['q']||[]).push(
arguments)},g[o]['t']=1*new Date})(window,'_googCsa');
</script>
<!-- Google Adsense Search AD end -->
<link rel="stylesheet" href="https://img3.doubanio.com/f/shire/75ba35fadc87ea9d052896f99e9de067746f9788/css/core/large.css">
<link rel="shortcut icon" href="https://img3.doubanio.com/favicon.ico" type="image/x-icon">
</head>
<body>
<script type="text/javascript">var _body_start = new Date();</script>
<link href="//img3.doubanio.com/dae/accounts/resources/d3e2921/shire/bundle.css" rel="stylesheet" type="text/css">
<div id="db-global-nav" class="global-nav">
<div class="bd">
<div class="top-nav-info">
<a href="https://accounts.douban.com/passport/login?source=main" class="nav-login" rel="nofollow">登录/注册</a>
</div>
<div class="top-nav-doubanapp">
<a href="https://www.douban.com/doubanapp/app?channel=top-nav" class="lnk-doubanapp">下载豆瓣客户端</a>
<div id="doubanapp-tip">
<a href="https://www.douban.com/doubanapp/app?channel=qipao" class="tip-link">豆瓣 <span class="version">6.0</span> 全新发布</a>
<a href="javascript: void 0;" class="tip-close">×</a>
</div>
<div id="top-nav-appintro" class="more-items">
<p class="appintro-title">豆瓣</p>
<p class="qrcode">扫码直接下载</p>
<div class="download">
<a href="https://www.douban.com/doubanapp/redirect?channel=top-nav&direct_dl=1&download=iOS">iPhone</a>
<span>·</span>
<a href="https://www.douban.com/doubanapp/redirect?channel=top-nav&direct_dl=1&download=Android" class="download-android">Android</a>
</div>
</div>
</div>
<div class="global-nav-items">
<ul>
<li class="on">
<a href="https://www.douban.com" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-main&quot;,&quot;uid&quot;:&quot;0&quot;}">豆瓣</a>
</li>
<li class="">
<a href="https://book.douban.com" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-book&quot;,&quot;uid&quot;:&quot;0&quot;}">读书</a>
</li>
<li class="">
<a href="https://movie.douban.com" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-movie&quot;,&quot;uid&quot;:&quot;0&quot;}">电影</a>
</li>
<li class="">
<a href="https://music.douban.com" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-music&quot;,&quot;uid&quot;:&quot;0&quot;}">音乐</a>
</li>
<li class="">
<a href="https://www.douban.com/location" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-location&quot;,&quot;uid&quot;:&quot;0&quot;}">同城</a>
</li>
<li class="">
<a href="https://www.douban.com/group" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-group&quot;,&quot;uid&quot;:&quot;0&quot;}">小组</a>
</li>
<li class="">
<a href="https://read.douban.com&#47;?dcs=top-nav&amp;dcm=douban" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-read&quot;,&quot;uid&quot;:&quot;0&quot;}">阅读</a>
</li>
<li class="">
<a href="https://douban.fm&#47;?from_=shire_top_nav" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-fm&quot;,&quot;uid&quot;:&quot;0&quot;}">FM</a>
</li>
<li class="">
<a href="https://time.douban.com&#47;?dt_time_source=douban-web_top_nav" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-time&quot;,&quot;uid&quot;:&quot;0&quot;}">时间</a>
</li>
<li class="">
<a href="https://market.douban.com&#47;?utm_campaign=douban_top_nav&amp;utm_source=douban&amp;utm_medium=pc_web" target="_blank" data-moreurl-dict="{&quot;from&quot;:&quot;top-nav-click-market&quot;,&quot;uid&quot;:&quot;0&quot;}">豆品</a>
</li>
</ul>
</div>
</div>
</div>
<script>
;window._GLOBAL_NAV = {
DOUBAN_URL: "https://www.douban.com",
N_NEW_NOTIS: 0,
N_NEW_DOUMAIL: 0
};
</script>
<script src="//img3.doubanio.com/dae/accounts/resources/d3e2921/shire/bundle.js" defer="defer"></script>
<link href="//img3.doubanio.com/dae/accounts/resources/d3e2921/sns/bundle.css" rel="stylesheet" type="text/css">
<div id="db-nav-sns" class="nav">
<div class="nav-wrap">
<div class="nav-primary">
<div class="nav-logo">
<a href="https://www.douban.com">豆瓣社区</a>
</div>
<div class="nav-search">
<form action="https://www.douban.com/search" method="get">
<fieldset>
<legend>搜索:</legend>
<label for="inp-query">搜索你感兴趣的内容和人...</label>
<div class="inp">
<input type="hidden" name="source" value="suggest">
<input id="inp-query" name="q" size="22" maxlength="60" autocomplete="off" value="">
</div>
<div class="inp-btn"><input type="submit" value="搜索"></div>
</fieldset>
</form>
</div>
<div class="nav-items">
<ul>
<li><a href="https://www.douban.com">首页</a></li>
<li>
<a href="https://www.douban.com/explore">
浏览发现
</a>
</li>
<li>
<a href="https://www.douban.com/gallery">
话题广场
<img src="https://img3.doubanio.com/f/shire/e49eca1517424a941871a2667a8957fd6c72d632/pics/new_menu.gif" alt="new" style="position: absolute; top: -7px; right: -13px;" />
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<script src="//img3.doubanio.com/dae/accounts/resources/d3e2921/sns/bundle.js" defer="defer"></script>
<div id="wrapper">
<div id="content">
<h1>搜索: 逃避可耻却有用</h1>
<div class="grid-16-8 clearfix">
<div class="article">
<div class="mod-search">
<form action="https://www.douban.com/search" method="get">
<fieldset>
<legend>搜索:</legend>
<input type="hidden" name="cat" value="1002">
<div class="inp"><input placeholder="搜索你感兴趣的内容和人" autofocus name="q" size="22" maxlength="60" value="逃避可耻却有用"></div>
<div class="inp-btn"><input type="submit" value="搜索"></div>
</fieldset>
</form>
</div>
<div class="search-cate">
<ul>
<li><a href="/search?q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">全部</a></li>
<li class=on><a href="/search?cat=1002&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">电影</a></li>
<li><a href="/search?cat=1001&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">书籍</a></li>
<li><a href="/search?cat=1003&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">音乐</a></li>
<li><a href="/search?cat=1019&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">小组</a></li>
<li><a href="/search?cat=1005&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">成员</a></li>
<li><a href="/search?cat=1015&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">日记</a></li>
<li><a href="/search?cat=2012&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">小站</a></li>
<li><a href="/search?cat=1011&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">同城活动</a></li>
<li><a href="/search?cat=3069&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">舞台剧</a></li>
<li><a href="/search?cat=3114&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">游戏</a></li>
<li><a href="/search?cat=3064&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">移动应用</a></li>
<li><a href="/search?cat=8018&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8">豆品</a></li>
</ul>
</div>
<script>
Do(function(){
if ($.browser.msie && ($.browser.version|0) === 6) {
return;
}
$(window).scroll((function(){var g=$(document);var d=$(".search-cate");var f=d.find("ul");var e=parseInt($("body").css("padding-top"))+5;var c=d.offset().top-e;var b=d.width();var a;return function(h){if(a){window.clearTimeout(a)}a=window.setTimeout(function(){if(g.scrollTop()>=c){d.css({height:1});f.css({position:"fixed",width:b,top:e})}else{d.css({height:"auto"});f.css({position:"static",width:"auto"})}},0)}})());
});
</script>
<div class="search-result">
<!-- douban ad begin -->
<div id="dale_search_promo"></div>
<!-- douban ad end -->
<h2>
相关电影:
</h2>
<div class="result-list">
<div class="result">
<div class="pic">
<a class="nbg" href="https://www.douban.com/link2/?url=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F26816519%2F&amp;query=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8&amp;cat_id=1002&amp;type=search&amp;pos=0" target="_blank" onclick="moreurl(this,{i: '0', query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_movie', sid: 26816519, qcat: '1002'})" title="逃げるは恥だが役に立つ" ><img src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2400201631.webp"></a>
</div>
<div class="content">
<div class="title">
<h3>
<span>[电影]</span>
&nbsp;<a href="https://www.douban.com/link2/?url=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F26816519%2F&amp;query=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8&amp;cat_id=1002&amp;type=search&amp;pos=0" target="_blank" onclick="moreurl(this,{i: '0', query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_movie', sid: 26816519, qcat: '1002'})" >逃避虽可耻但有用 </a>
<span class="ic-mark ic-movie-mark">可播放</span>
</h3>
<div class="rating-info">
<span class="allstar40"></span>
<span class="rating_nums">8.4</span>
<span>(154381人评价)</span>
<span class="subject-cast">原名:逃げるは恥だが役に立つ / 金子文纪 / 新垣结衣 / 2016</span>
</div>
</div>
<p>森山实栗(新垣结衣 饰)自研究生毕业之后就一直仕途不顺,最近更是惨遭解雇,处于“无业游民”的状态之下,日子过得十分凄惨。经由父亲的介绍,无处可去的实栗来到了名...</p>
</div>
</div>
<div class="gallery_topic_result">
<div class="item">
<div class="label">话题</div>
<div class="detail">
<h2><a href="/gallery/topic/13555/?from=search" target="_blank" onclick="moreurl(this,{query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_topic', tid: 13555, qcat: '1002'})">《逃避虽可耻但有用》哪个角色最让你惊喜?</a></h2>
<div class="info">9794人浏览 · 14篇文章</div>
</div>
</div>
<div class="item">
<div class="label">话题</div>
<div class="detail">
<h2><a href="/gallery/topic/13554/?from=search" target="_blank" onclick="moreurl(this,{query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_topic', tid: 13554, qcat: '1002'})">《逃避虽可耻但有用》有哪些精彩片段?</a></h2>
<div class="info">722人浏览 · 0篇文章</div>
</div>
</div>
</div>
<div class="result">
<div class="pic">
<a class="nbg" href="https://www.douban.com/link2/?url=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F35211578%2F&amp;query=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8&amp;cat_id=1002&amp;type=search&amp;pos=1" target="_blank" onclick="moreurl(this,{i: '1', query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_movie', sid: 35211578, qcat: '1002'})" title="逃げるは恥だが役に立つ ガンバレ人類! 新春スペシャル!!" ><img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2629717359.webp"></a>
</div>
<div class="content">
<div class="title">
<h3>
<span>[电影]</span>
&nbsp;<a href="https://www.douban.com/link2/?url=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F35211578%2F&amp;query=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8&amp;cat_id=1002&amp;type=search&amp;pos=1" target="_blank" onclick="moreurl(this,{i: '1', query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_movie', sid: 35211578, qcat: '1002'})" >逃避虽可耻但有用 新春特别篇 </a>
</h3>
<div class="rating-info">
<span class="allstar40"></span>
<span class="rating_nums">8.4</span>
<span>(26905人评价)</span>
<span class="subject-cast">原名:逃げるは恥だが役に立つ ガンバレ人類! 新春スペシャル!! / 金子文纪 / 新垣结衣 / 2021</span>
</div>
</div>
<p>森山实栗(新垣结衣 饰)和津崎平匡(星野源 饰)之间的事实婚姻愉快而又轻松的进行着,在日常生活的摩擦中,他们逐渐接受了彼此不同的生活步调,关系越来越亲密融洽。...</p>
</div>
</div>
<div class="result">
<div class="pic">
<a class="nbg" href="https://www.douban.com/link2/?url=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F35071038%2F&amp;query=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8&amp;cat_id=1002&amp;type=search&amp;pos=2" target="_blank" onclick="moreurl(this,{i: '2', query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_movie', sid: 35071038, qcat: '1002'})" title="逃げるは恥だが役に立つ ムズキュン!特別編" ><img src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2649905266.webp"></a>
</div>
<div class="content">
<div class="title">
<h3>
<span>[电影]</span>
&nbsp;<a href="https://www.douban.com/link2/?url=https%3A%2F%2Fmovie.douban.com%2Fsubject%2F35071038%2F&amp;query=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8&amp;cat_id=1002&amp;type=search&amp;pos=2" target="_blank" onclick="moreurl(this,{i: '2', query: '%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8', from: 'dou_search_movie', sid: 35071038, qcat: '1002'})" >逃避虽可耻但有用 爱的悸动!特别篇 </a>
</h3>
<div class="rating-info">
<span class="allstar45"></span>
<span class="rating_nums">8.9</span>
<span>(1179人评价)</span>
<span class="subject-cast">原名:逃げるは恥だが役に立つ ムズキュン!特別編 / 金子文纪 / 新垣结衣 / 2020</span>
</div>
</div>
<p>本特别篇为2016年10月首播的《逃避虽可耻但有用》原剧的再剪辑版在首播版的基础上加入了一些未公开镜头。</p>
</div>
</div>
</div>
</div>
<div class="back-to-top">
<a href="#">&#8593;回顶部</a>
</div>
<script>
Do(function() {
$("html").delegate(".a_search_more","click",function(c){c.preventDefault();var b=$(this);if(b.hasClass("processing")){return}var a=b.data();b.attr("title",b.text()).text("加载中...");b.addClass("processing");$.get("/j/search",a,function(d){if(d.r){b.text("加载失败...");return}b.removeClass("processing");b.text(b.attr("title"));b.data("start",parseInt(b.data("start"),10)+d.limit);$(d.items.join("")).insertBefore(b.parent());if(!d.more){b.hide()}})});
(function(){var h=$(window);var k=$(document);var l;var a=$(".back-to-top");var b=$("#content").find(".article");var g;var i=$("#content").find(".search-result");var d=$.browser.msie&&$.browser.version==="6.0";var f=function(n){if(!f.cache){f.cache=[]}if(f.cache[n]){return}var m=new Date;(new Image()).src="/stat.html?source=group&action=back_top&iden="+n+"&month="+(m.getMonth()+1)+"&day="+m.getDate()+"&timestamp="+(+new Date);f.cache[n]=1};var e=function(){return i.offset().top+i.outerHeight()};var c=function(m){if(m+g>=e()){a.css({position:"absolute",bottom:"",top:e()-a.outerHeight()})}else{if(!d){a.css({position:"fixed",top:"",bottom:0})}}a.show().find("a").stop().animate({top:0})};var j=function(){a.hide().find("a").css("top",40)};h.resize(function(){g=h.height();a.css("left",b.offset().left+b.width()+80);l=k.height()/g>3?Math.max(2*g,$(".side").height()):0});h.trigger("resize");h.scroll((function(){var m;return function(){if(m){clearTimeout(m)}setTimeout(function(){if(l===0){return}var n=k.scrollTop();if(n>l){c(n)}else{j()}},100)}})());a.find("a").click(function(m){m.preventDefault();k.scrollTop(0)});if(d){h.scroll(function(){if(k.scrollTop()+g>=e()){return}a.css("top",k.scrollTop()+g-a.height())})}})();
});
</script>
</div>
<div class="aside">
<!-- douban ad begin -->
<div id="dale_subject_search_top_right"></div>
<!-- douban ad end -->
<div class="mod">
<div class="hd">
<h2>
豆瓣还没有这个电影,我来添加
&nbsp;&middot;&nbsp;&middot;&nbsp;&middot;&nbsp;&middot;&nbsp;&middot;&nbsp;&middot;
</h2>
</div>
<div class="bd">
<p class="pl">
<a href="https://movie.douban.com/new_subject?cat=1002&amp;search_text=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8" rel="nofollow">&gt;&nbsp;添加电影</a>
</p>
<p class="pl">
<a href="https://movie.douban.com/celebrities/new?step=1&amp;search_text=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8" rel="nofollow">&gt;&nbsp;添加影人</a>
</p>
</div>
</div>
<div class="search_report">
<a href="javascript:;" id="search-report-btn">&gt; 对结果不满意?让我们知道</a>
</div>
<iframe frameborder="0" id="feedback-iframe"></iframe>
<script type="text/javascript">
Do(function () {
$('#search-report-btn').click(function () {
var url = 'https://help.douban.com/feedback_popup?qtype=194&tags=%E7%BB%BC%E5%90%88%2C%E7%94%B5%E5%BD%B1&extra=' +
encodeURIComponent(JSON.stringify({
q: '逃避可耻却有用',
cat_id: '1002'
}))
var $iframe = $('#feedback-iframe')
if ($iframe.attr('src') !== url) {
$iframe.attr('src', url)
}
$('#feedback-iframe').show()
})
window.addEventListener('message', function (event) {
var origin = event.origin || event.originalEvent.origin;
if (!origin.match(/^https?:\/\/[a-z0-9-.]+\.douban\.com(?:\/|:|$)/)) {
// 非法域名
window.console && console.warn && console.warn('window receive message from illegal origin: ', origin, event)
return
}
if (typeof event.data !== 'string') {
return
}
var data = JSON.parse(event.data)
if (data.type === 'FEEDBACK_POPUP_CLOSE') {
$('#feedback-iframe').hide()
}
})
});
</script>
</div>
<div class="extra">
</div>
</div>
</div>
<div id="footer">
<span id="icp" class="fleft gray-link">
&copy; 20052021 douban.com, all rights reserved 北京豆网科技有限公司
</span>
<a href="https://www.douban.com/hnypt/variformcyst.py" style="display: none;"></a>
<span class="fright">
<a href="https://www.douban.com/about">关于豆瓣</a>
· <a href="https://www.douban.com/jobs">在豆瓣工作</a>
· <a href="https://www.douban.com/about?topic=contactus">联系我们</a>
· <a href="https://www.douban.com/about/legal">法律声明</a>
· <a href="https://help.douban.com/?app=main" target="_blank">帮助中心</a>
· <a href="https://www.douban.com/doubanapp/">移动应用</a>
· <a href="https://www.douban.com/partner/">豆瓣广告</a>
</span>
</div>
</div>
<!-- COLLECTED JS -->
<!-- douban ad begin -->
<script type="text/javascript">
(function (global) {
var newNode = global.document.createElement('script'),
existingNode = global.document.getElementsByTagName('script')[0],
adSource = '//erebor.douban.com/',
userId = '',
browserId = 'kZhpqD1n6oY',
criteria = '8:逃避可耻却有用|3:/search?cat=1002&amp;q=%E9%80%83%E9%81%BF%E5%8F%AF%E8%80%BB%E5%8D%B4%E6%9C%89%E7%94%A8',
preview = '',
debug = false,
adSlots = ['dale_subject_search_top_right', 'dale_search_promo', 'dale_web_search_result_feed'];
global.DoubanAdRequest = {src: adSource, uid: userId, bid: browserId, crtr: criteria, prv: preview, debug: debug};
global.DoubanAdSlots = (global.DoubanAdSlots || []).concat(adSlots);
newNode.setAttribute('type', 'text/javascript');
newNode.setAttribute('src', '//img1.doubanio.com/YWVrMm1iYy9mL2FkanMvN2ZmNmEyM2M0ZDNjMmQxYWVkMjMwZDIwMDU5NWI2YTFkNDc5YjExYi9hZC5yZWxlYXNlLmpz');
newNode.setAttribute('async', true);
existingNode.parentNode.insertBefore(newNode, existingNode);
})(this);
</script>
<!-- douban ad end -->
<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-5WP579" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-5WP579');</script>
<!-- End Google Tag Manager -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var p=(('https:' == document.location.protocol) ? 'https' : 'http'), u=p+'://fundin.douban.com/';
_paq.push(['setTrackerUrl', u+'piwik']);
_paq.push(['setSiteId', '100001']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript';
g.defer=true;
g.async=true;
g.src=p+'://img3.doubanio.com/dae/fundin/piwik.js';
s.parentNode.insertBefore(g,s);
})();
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-7019765-1']);
_gaq.push(['_setCampNameKey', 'dcn']);
_gaq.push(['_setCampSourceKey', 'dcs']);
_gaq.push(['_setCampMediumKey', 'dcm']);
_gaq.push(['_setCampTermKey', 'dct']);
_gaq.push(['_setCampContentKey', 'dcc']);
_gaq.push(['_addOrganic', 'baidu', 'word']);
_gaq.push(['_addOrganic', 'soso', 'w']);
_gaq.push(['_addOrganic', '3721', 'name']);
_gaq.push(['_addOrganic', 'youdao', 'q']);
_gaq.push(['_addOrganic', 'so.360.cn', 'q']);
_gaq.push(['_addOrganic', 'vnet', 'kw']);
_gaq.push(['_addOrganic', 'sogou', 'query']);
_gaq.push(['_addIgnoredOrganic', '豆瓣']);
_gaq.push(['_addIgnoredOrganic', 'douban']);
_gaq.push(['_addIgnoredOrganic', '豆瓣网']);
_gaq.push(['_addIgnoredOrganic', 'www.douban.com']);
_gaq.push(['_setDomainName', '.douban.com']);
_gaq.push(['_setCustomVar', 1, 'responsive_view_mode', 'desktop', 3]);
_gaq.push(['_trackPageview']);
_gaq.push(['_trackPageLoadTime']);
window._ga_init = function() {
var ga = document.createElement('script');
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
ga.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(ga);
};
if (window.addEventListener) {
window.addEventListener('load', _ga_init, false);
} else {
window.attachEvent('onload', _ga_init);
}
</script>
<!-- dae-web-bywater--default-65879cbd8c-clxtd-->
<script>_SPLITTEST=''</script>
</body>
</html>

View File

@@ -214,3 +214,12 @@ class AnnouncementResource:
def add_announcement(self, username, content, ip, browser):
pass
class DoubanResource:
def get_douban_data(self, rid: int) -> dict:
pass
def get_douban_image(self, rid: int) -> bytes:
pass

View File

@@ -13,6 +13,7 @@ import os
import re
import time
import importlib
import filetype
from concurrent.futures import ThreadPoolExecutor
from datetime import date, timedelta
@@ -586,3 +587,32 @@ class DBDumpHandler(BaseHandler):
def get(self):
resp = yield self.get_hash()
self.write(resp)
class DoubanHandler(BaseHandler):
class_name = f"Douban{adapter}Resource"
# from Mongo import DoubanMongoResource
# instance = DoubanMongoResource()
@run_on_executor()
def douban_data(self):
rid = self.get_query_argument("resource_id")
data = self.instance.get_douban_data(int(rid))
data.pop("poster_data")
return data
def get_image(self) -> bytes:
rid = self.get_query_argument("resource_id")
return self.instance.get_douban_image(int(rid))
@gen.coroutine
def get(self):
_type = self.get_query_argument("type", None)
if _type == "image":
data = self.get_image()
self.set_header("content-type", filetype.guess_mime(data))
self.write(data)
else:
resp = yield self.douban_data()
self.write(resp)

View File

@@ -20,7 +20,7 @@ from tornado import web, httpserver, ioloop, options
from Mongo import OtherMongoResource
from handler import IndexHandler, UserHandler, ResourceHandler, TopHandler, UserLikeHandler, NameHandler, \
CommentHandler, AnnouncementHandler, CaptchaHandler, MetricsHandler, GrafanaIndexHandler, GrafanaSearchHandler, \
GrafanaQueryHandler, BlacklistHandler, NotFoundHandler, DBDumpHandler,CommentChildHandler
GrafanaQueryHandler, BlacklistHandler, NotFoundHandler, DBDumpHandler, CommentChildHandler, DoubanHandler
enable_pretty_logging()
@@ -48,6 +48,7 @@ class RunServer:
(r'/api/db_dump', DBDumpHandler),
(r'/api/announcement', AnnouncementHandler),
(r'/', IndexHandler),
(r'/api/douban', DoubanHandler),
(r'/(.*\.html|.*\.js|.*\.css|.*\.png|.*\.jpg|.*\.ico|.*\.gif|.*\.woff2|.*\.gz|.*\.zip|.*\.svg|.*\.json)',
web.StaticFileHandler,
{'path': static_path}),