// ==UserScript==
// @name 豆瓣电影同步到Notion
// @namespace https://greasyfork.org/zh-CN/scripts/464467-%E8%B1%86%E7%93%A3%E8%AF%BB%E4%B9%A6%E5%90%8C%E6%AD%A5%E5%88%B0notion
// @version 1.6
// @description 抓取豆瓣电影信息,基于Notion搭建私人电影管理系统
// @author @Yanwudong https://twitter.com/yanwudong
// @match https://movie.douban.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=douban.com
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @license GNU GPLv3
// ==/UserScript==
(function() {
'use strict';
// 添加CSS样式
GM_addStyle(`
.toast {
position: fixed;
top: 150px;
right: 50%;
z-index: 9999;
opacity: 0;
transition: opacity 0.2s ease-in-out;
}
.toast.show {
opacity: 1;
}
.toast-body {
background-color: #f2f8f2;
//border: 1px solid #ccc;
//border-radius: 3px;
color:#4f946e;
padding: 2px;
padding-left:10px;
padding-right:10px
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}
#nlog {
top: 130px;
right: 50%;
z-index: 9999;
opacity: 0;
transition: opacity 0.2s ease-in-out;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
background: #fff;
overflow: hiadden;
padding: 40px 30px 30px;
position: fixed;
display : none;
}
#nlog.show {
opacity: 1;
}
.form-group{
margin-bottom: 10px;
}
.form-control{
border: 1px solid #e4e6e5;
border-radius: 3px;
box-sizing: border-box;
font-size: 13px;
padding: 10px;
width: 280px;
}
#exampleModalLabel{
cursor: pointer;
font-size: 18px;
line-height: 2;
text-align: center;
border-bottom: 2px solid #494949;
color: #333;
font-weight: 600;
margin-bottom:20px;
}
#twitter{
margin-left:30px;
}
#saveBtn{
background-color: #41ac52;
border: 1px solid #b9dcd0;
color: #fff;
cursor: default;
font-size: 15px;
font-weight: 600;
padding: 0;
width:79%;
}
.modal-footer button{
height:36px;
width:19%;
margin-bottom:20px;
}
#syncbt {
display: inline-block;
margin-left: 10px;
font-size: 13px;
color:#4f946e;
background-color: #f2f8f2;
padding: 2px;
padding-left: 8px;
padding-right: 8px;
border: 1px solid #b9dcd0;
border-radius:3px
}
#syncbt:hover {
cursor: pointer;
}
#setbt {
display: inline-block;
margin-left: 5px;
font-size: 13px;
color:#4f946e;
background-color: #f2f8f2;
padding: 2px;
border: 1px solid #b9dcd0;
border-radius:3px
}
`);
// 创建一个 Modal
const modalHtml = `
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Notion Api 设置</h5>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<input type="text" class="form-control" id="apiInput" placeholder="token">
</div>
<div class="form-group">
<input type="text" class="form-control" id="pageIdInput" placeholder="页面 ID">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="saveBtn">保存设置</button>
<button type="button" class="btn btn-secondary" id="closeBtn" data-dismiss="modal">关闭</button>
</div>
<div class="modal-bottom">
<a href="https://seemly-pear-9fc.notion.site/Notion-e0ae1a1d391143abb9ff383730649149" id="refBtn" target="_blank";>操作说明</a>
<a href="https://twitter.com/yanwudong" id="twitter" target="_blank";>推特</a>
</div>
</div>
</div>
</div>
`;
//GM_setValue('nToken', nToken);
//GM_setValue('MdatabaseId', MdatabaseId);
//GM_setValue('databaseId', databaseId);
//初始化用户信息
var nToken = GM_getValue('nToken');
var pageId = GM_getValue('pageId');
//电影数据库Id
var MdatabaseId = GM_getValue('MdatabaseId');
const notionVersion = '2022-06-28';
// 创建一个轻提示框元素
const toast = document.createElement('div');
toast.id = 'toast';
toast.className = 'toast';
toast.innerHTML =`
<div class="toast-body">
🎉 同步成功!
</div>
`;
// 将轻提示框添加到页面中
document.body.appendChild(toast);
//创建一个授权框,让用户输入ApiKey和PageId
const nlog = document.createElement('div');
nlog.id = 'nlog';
nlog.innerHTML = modalHtml;
document.body.appendChild(nlog);
nlog.classList.add('show');
// 等待页面加载完成后执行
$(document).ready(function() {
// 给按钮添加点击事件
$('#saveBtn').click(function() {
nToken = $('#apiInput').val();
pageId = $('#pageIdInput').val();
GM_setValue('nToken', nToken);
GM_setValue('pageId', pageId);
//用户第一次使用先创建数据库
createDatabase();
nlog.style.display = 'none';
});
$('#closeBtn').click(function(){
nlog.style.display = 'none';
});
});
//检查用户是否登录
const checkUserInfo = () =>{
// 如果用户没有输入过信息,弹出输入框让其输入
if (!nToken || !pageId || !MdatabaseId ) {
nlog.style.display = 'block';
}else{
syncToNotion();
}
}
//添加同步按钮到页面
function addButton(){
const button = document.createElement('button');
button.innerText = '同步到Notion';
button.onclick = checkUserInfo;
const actions = document.querySelector('#content > h1 > .year ');//在电影名称后面加按钮
//debugger
actions.insertAdjacentElement('afterend',button);
button.id = 'syncbt';
};
//获取电影信息
function getMovieInfo(){
const infos = document.querySelectorAll('#info .pl');
let movie = {};
// 创建类型数组
let type = '';
let typeList = [];
debugger
movie['电影名'] = document.querySelector('#content > h1 > span').innerText;
movie['封面'] = document.querySelector('#mainpic > a > img').src;
const grade = document.querySelector('.rating_num');
if(grade != null){
movie['评分'] = document.querySelector('.rating_num').innerText;
}
movie['豆瓣链接']=window.location.href;
movie['简介']=document.querySelector('#link-report-intra').innerText;
debugger
//循环遍历infos,并把每个元素赋值给info
for(const info of infos){
if(info.innerText === '导演'){
movie['导演'] = info.nextSibling.nextSibling.innerText
}else if(info.innerText === '编剧'){
movie['编剧'] = info.nextSibling.nextSibling.innerText
}else if(info.innerText === '主演'){
movie['主演'] = info.nextSibling.nextSibling.innerText
}else if(info.innerText === '上映日期:'){
movie['上映日期'] = info.nextSibling.nextSibling.innerText
}else if(info.innerText === '片长:'){
movie['片长'] = info.nextSibling.nextSibling.innerText
}else if(info.innerText === '类型:'){
// 找到所有具有属性 "property" 且属性值为 "v:genre" 的元素
const genreElements = document.querySelectorAll('span[property="v:genre"]');
// 遍历每个元素,将其内容添加到数组中
genreElements.forEach(function(element) {
typeList.push(element.textContent.trim());
});
movie['类型'] = typeList
}else{
let prop = info.innerText.substr(0,info.innerText.length-1)
movie[prop] = info.nextSibling.data
}
}
return movie
}
// 同步电影信息到Notion
function syncToNotion(){
const movie = getMovieInfo();
createMovieItem(movie);
}
//创建页面电影子数据库database
async function createDatabase() {
const body = {
'parent': { 'type': 'page_id', 'page_id': pageId },
'title': [
{
'type': 'text',
'text': {
'content': 'MovieList',
'link': null
}
}
],
'icon':{
'type':'emoji',
'emoji':'🍿'
},
'properties': {
'电影名': {
'title': {}
},
'类型':{
'multi_select':{
'options':[
{
'name':'其他',
'color':'default'
}
]
}
},
'地区':{
'select':{
'options':[
{
'name':'其他',
'color':'default'
}
]
}
},
'状态':{
'select':{
'options':[
{
'name':'🌑想看',
'color':'purple'
},
{
'name':'🌒在看',
'color':'orange'
},
{
'name':'🌕看过',
'color':'green'
}
]
}
},
'个人打分':{
'select':{
'options':[
{
'name':'⭐️⭐️⭐️⭐️⭐️'
},
{
'name':'⭐️⭐️⭐️⭐️'
},
{
'name':'⭐️⭐️⭐️'
},
{
'name':'⭐️⭐️'
},
{
'name':'⭐️'
}
]
}
},
'导演': {
'rich_text': {}
},
"创建时间": {
"type": "created_time",
"created_time": {}
},
'主演': {
'rich_text': {}
},
'简介': {
'rich_text': {}
},
'上映日期': {
'rich_text': {}
},
'片长': {
'number': {
'format': 'number'
}
},
'豆瓣评分': {
'number': {
'format': 'number'
}
},
'IMDb': {
'rich_text': {}
},
'封面': {
'files': {}
},
'豆瓣链接': {
'url': {}
},
'简介': {
'rich_text': {}
},
}
};
const options = {
headers: {
Authorization: 'Bearer ' + nToken,
'Notion-Version': notionVersion,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
GM_xmlhttpRequest({
method: 'POST',
url: 'https://api.notion.com/v1/databases',
headers: options.headers,
data: options.body,
onload: function(response) {
const res = JSON.parse(response.responseText);
if (res.object === 'error') {
alert(res.message);
} else {
GM_setValue('MdatabaseId',res.id);
MdatabaseId = res.id;
toast.innerHTML =`
<div class="toast-body">
🎉 配置成功!
</div>
`;
// 显示轻提示框
toast.classList.add('show');
// 3秒后隐藏轻提示框
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
}
});
}
//同步电影
function createMovieItem(movie) {
// 构建用于传递给 Notion 数据库的标签数据
const tagsProperties = movie['类型'].map(tag => {
return { name: tag };
});
const body = {
'parent': { 'type': 'database_id', 'database_id': MdatabaseId },
'icon':{
'type':'emoji',
'emoji':'🎞️'
},
'properties': {
'电影名': {
'type': 'title',
'title': [{ 'type': 'text', 'text': { 'content': movie['电影名'] } }]
},
'封面': {
'files': [
{
'type': 'external',
'name': 'cover',
'external': { 'url': movie['封面']}
},
]
},
'IMDb': {
'type': 'rich_text',
'rich_text': [{ 'type': 'text', 'text': { 'content': movie['IMDb'] ? movie['IMDb']:'' } }]
},
'片长': {
'number': parseInt(movie['片长'] ? movie['片长']:'' )
},
'状态':{
select:{
'name':'🌑想看'
}
},
'上映日期': {
'type':'rich_text',
'rich_text': [{ 'type': 'text', 'text': { 'content': movie['上映日期'] ? movie['上映日期']:'' } }]
} ,
'豆瓣评分': {
'number': parseFloat(movie['评分'])
},
'导演': {
'type': 'rich_text',
'rich_text': [{ 'type': 'text', 'text': { 'content': movie['导演'] ? movie['导演']:''} }]
},
'主演': {
'type': 'rich_text',
'rich_text': [{ 'type': 'text', 'text': { 'content': movie['主演'] ? movie['主演']:''} }]
},
'简介': {
'type': 'rich_text',
'rich_text': [{ 'type': 'text', 'text': { 'content': movie['简介'] ? movie['简介']:''} }]
},
'地区':{
select:{
'name':movie['制片国家/地区'] ? movie['制片国家/地区']:''
}
},
'类型': {
"multi_select":tagsProperties
},
'封面': {
'files': [
{
'type': 'external',
'name': 'cover',
'external': { 'url': movie['封面']}
},
]
},
'豆瓣链接':{
'type':'url',
'url':movie['豆瓣链接']
}
},
};
//传参数
const options = {
headers: {
Authorization: 'Bearer ' + nToken,
'Notion-Version': notionVersion,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
GM_xmlhttpRequest({
method: 'POST',
url: 'https://api.notion.com/v1/pages',
headers: options.headers,
data: options.body,
onload: function(response) {
debugger
const res = JSON.parse(response.responseText);
if (res.object === 'error') {
alert(res.message);
} else {
toast.innerHTML =`
<div class="toast-body">
🎉 同步成功!
</div>
`;
// 显示轻提示框
toast.classList.add('show');
// 3秒后隐藏轻提示框
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
}
});
}
addButton();
})();