├── imgs
├── demo.jpg
└── douban.jpg
├── download
├── douban-movie-v1.0.crx
├── douban-movie-v1.1.crx
└── douban-movie-v1.2.crx
├── gulpfile.js
├── package.json
├── LICENSE
├── .gitignore
├── README.md
└── src
├── background.js
└── core.js
/imgs/demo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinple/douban-movie-extension/HEAD/imgs/demo.jpg
--------------------------------------------------------------------------------
/imgs/douban.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinple/douban-movie-extension/HEAD/imgs/douban.jpg
--------------------------------------------------------------------------------
/download/douban-movie-v1.0.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinple/douban-movie-extension/HEAD/download/douban-movie-v1.0.crx
--------------------------------------------------------------------------------
/download/douban-movie-v1.1.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinple/douban-movie-extension/HEAD/download/douban-movie-v1.1.crx
--------------------------------------------------------------------------------
/download/douban-movie-v1.2.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinple/douban-movie-extension/HEAD/download/douban-movie-v1.2.crx
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var uglify = require('gulp-uglify');
3 |
4 | gulp.task('compress', function () {
5 | return gulp.src(['src/core.js', 'src/background.js'])
6 | .pipe(uglify())
7 | .pipe(gulp.dest('tmp'))
8 | .pipe(gulp.dest('build'));
9 | });
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "douban-movie-extension",
3 | "version": "1.2.0",
4 | "description": "妈妈再也不会担心我找不到资源了~",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/Neulana/douban-movie-extension.git"
8 | },
9 | "author": "Neulana",
10 | "license": "MIT",
11 | "bugs": {
12 | "url": "https://github.com/Neulana/douban-movie-extension/issues"
13 | },
14 | "homepage": "https://github.com/Neulana/douban-movie-extension#readme",
15 | "devDependencies": {
16 | "gulp": "^4.0.0",
17 | "gulp-concat": "^2.6.1",
18 | "gulp-uglify": "^2.0.0",
19 | "gulp-watch": "^4.3.10",
20 | "pump": "^1.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Neulana
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | *.zip
64 | tmp
65 |
66 | *.pem
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

2 |
3 | # 豆瓣电影传送门
4 |
5 | 我是一名豆瓣爱好者,常常在豆瓣APP上面标记想看的电影,然后在有空的时候再去找资源看。豆瓣最近新增了”在哪儿看这部电影“版块,但是仅仅收录了比较常见的几家视频网站,比如优酷、腾讯视频等,这些网站往往需要购买VIP才能观看,为了节约花在找资源上的时间,我写了这个”豆瓣电影传送门“Chrome插件,妈妈再也不会担心我找不到电影资源了~🍻🍻🍻
6 |
7 | # 使用效果
8 |
9 | 如图,在豆瓣电影页面的右边栏增加”豆瓣电影传送门“模块:
10 |
11 | 
12 |
13 | # TODO列表
14 | - 近日(2019年03月22日)发现本插件依赖的网站[neets](https://neets.cc/)在搜索结果里不再展示小网站(可能因为版权原因),严重影响了该插件的想要达到的效果。所以需要自己写搜索API来支持该插件。
15 |
16 | # 如何使用
17 |
18 | 提供两种下载方式。
19 |
20 | 方式一,Chrome官方商店:
21 |
22 | 需要翻墙,直接前往 [Chrome商店](https://chrome.google.com/webstore/detail/豆瓣电影传送门/pkidecliagangmpphpelecaoogfbnihi ) 下载;
23 |
24 | 方式二,手动安装:
25 |
26 | 1. 点击[download文件夹](https://github.com/Neulana/douban-movie-extension/tree/master/download)下载最新版本到本地;
27 | 2. 打开Chrome,在地址栏输入chrome://extensions/,回车;
28 | 3. 打开右上角的”开发者模式“开关;
29 | 4. 将已下载的crx文件拖入Chrome扩展程序窗口;
30 | 5. 打开任意电影的[豆瓣主页](https://movie.douban.com/subject/26647117/),右边就会出现”豆瓣电影传送门“版块
31 | 6. 你就可以愉快的看电影了🎉🎉🎉
32 |
33 | **说明**:有版本更新时,可在浏览器地址栏右侧找到本插件的图标,鼠标右键选择”从Chrome中移除...“,然后,再重复以上6个步骤即可,请关注本repo~
34 |
35 | # 感谢
36 |
37 | - 灵感来自 [Ovilia](https://github.com/Ovilia/readfree-chrome-extension) ;
38 | - 感谢 [zhaopengme](https://github.com/zhaopengme) 帮忙发布到Chrome商店。
39 |
40 |
41 | # 反馈
42 |
43 | 如果使用过程中发现问题,请提 [issue](https://github.com/Neulana/douban-movie-extension/issues)
44 |
45 | 欢迎 **fork & star**
46 |
47 | 1. **Windows电脑上手动安装报错**
48 |
49 | 已解决,请参考:https://github.com/Neulana/douban-movie-extension/issues/1
50 |
51 | # 更新日志
52 |
53 | ## v1.2
54 |
55 | - 剔除AcFun和哔哩哔哩网站来源,因为这些网站常有电影剪辑视频,而非正片,这不是我想要的;
56 | - 列表默认展示的来源条目数量增加至15条。
57 |
58 | # 免责声明
59 | 该插件仅限个人学习使用,严禁用于商业用途,否则后果自负;视频来自第三方网站,与我本人无关。
60 |
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | var cached = {};
2 |
3 | chrome.runtime.onConnect.addListener(function (port) {
4 | if (port.name == "douban-movie") {
5 | port.onMessage.addListener(function (msg) {
6 | if (cached[msg.url]) {
7 | port.postMessage(cached[msg.url]);
8 | return;
9 | }
10 | var xhr = new XMLHttpRequest();
11 | xhr.onload = function () {
12 | if (xhr.status == 200) {
13 | var resp = JSON.parse(xhr.responseText);
14 | var resoures = resp['list'];
15 | if (resoures && resoures[0]) {
16 | msg.neetLinks = [];
17 | for (var i = 0; i < resoures.length; i++) {
18 | var themes = resoures[i]['themes'];
19 | if (themes && themes[0]) {
20 | var domainName = themes[0]['domainName'];
21 | var auxiliaryInfo = themes[0]['auxiliaryInfo'];
22 | var videoUrl = themes[0]['videoUrl'];
23 | msg.neetLinks.push([domainName, auxiliaryInfo, videoUrl]);
24 | }
25 | }
26 | msg.success = true;
27 | port.postMessage(msg);
28 | cached[msg.url] = msg;
29 | } else {
30 | msg.success = false;
31 | port.postMessage(msg);
32 | cached[msg.url] = msg;
33 | }
34 | }
35 | };
36 | xhr.open('GET', msg.url, true);
37 | xhr.setRequestHeader('Content-type', 'text/html');
38 | xhr.send();
39 | });
40 | }
41 | });
--------------------------------------------------------------------------------
/src/core.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | var port = null;
4 | var dict = {};
5 | var repoIssuesAddr = 'https://github.com/Neulana/douban-movie-extension/issues';
6 |
7 | // search with movie name
8 | function search(movieName, parentTag) {
9 | if (!port || port.name != 'douban-movie') {
10 | port = chrome.runtime.connect({
11 | name: 'douban-movie'
12 | });
13 | port.onMessage.addListener(function (msg) {
14 | var url = msg.url;
15 | var num = url.search("&key=");
16 | var searchUrl = 'https://neets.cc/search?page-size=6&type=2&key=' + url.substring(num+5);
17 | var neetLinks = msg.neetLinks;
18 | if (!msg.success) {
19 | dict[url].found = false;
20 | return;
21 | }
22 | dict[url].found = true;
23 | var task;
24 | while (dict[url].tasks.length > 0) {
25 | task = dict[url].tasks.pop();
26 | var panel = getPanel(searchUrl, neetLinks);
27 | task.parentTag.insertBefore(panel, task.parentTag.childNodes[0]);
28 | }
29 | });
30 | }
31 | var url = 'https://smartapi.neets.cc/full-texts/grab-datas?pageNo=1&pageSize=15&seriesSize=9&themeSize=3&key=' + movieName;
32 | if (!dict[url]) {
33 | dict[url] = {
34 | tasks: []
35 | };
36 | }
37 | if (dict[url].found) {
38 | // var panel = getPanel(url);
39 | // parentTag.appendChild(panel);
40 | } else if (dict[url].found == undefined) {
41 | dict[url].tasks.push({
42 | parentTag: parentTag
43 | });
44 | port.postMessage({
45 | url: url
46 | });
47 | }
48 | }
49 |
50 | function getPanel(rawUrl, neetLinks) {
51 | var exclude_sites = ["acfun.cn", "bilibili.com"]; //避免抓取到同名剪辑短片
52 | var neetsDiv = document.createElement('div');
53 | var neetsH2 = document.createElement('h2');
54 | var feedBack = document.createElement('a');
55 | neetsDiv.setAttribute('class', 'gray_ad');
56 | neetsH2.innerText = '豆瓣电影传送门 · · · · · ·'
57 | feedBack.setAttribute('href', repoIssuesAddr);
58 | feedBack.setAttribute('target', '_blank');
59 | feedBack.setAttribute('class', 'report-error');
60 | feedBack.innerText = '反馈';
61 | neetsDiv.appendChild(neetsH2);
62 | neetsDiv.appendChild(feedBack);
63 | var neetsUl = document.createElement('ul');
64 | neetsUl.setAttribute('class', 'bs');
65 | for (var i = 0; i < neetLinks.length; i++) {
66 | var href_url = neetLinks[i][2];
67 | var exclude_mark = false; //用来跳出本轮循环
68 | for (var j = 0; j < exclude_sites.length; j++){
69 | if (href_url.indexOf(exclude_sites[j]) != -1) {
70 | console.log("url: " + href_url);
71 | exclude_mark = true;
72 | }
73 | }
74 | if (exclude_mark == true) {
75 | continue;
76 | }
77 | var neetsLi = document.createElement('li');
78 | var neetsMovie = document.createElement('a');
79 | var neetsSpan = document.createElement('span');
80 | var auxiliaryInfo = neetLinks[i][1];
81 | neetsMovie.setAttribute('href', href_url);
82 | neetsMovie.setAttribute('target', '_blank');
83 | neetsMovie.setAttribute('class', 'playBtn');
84 | neetsMovie.innerHTML = neetLinks[i][0];
85 | neetsSpan.setAttribute('class', 'buylink-price');
86 | auxiliaryInfo = auxiliaryInfo.replace(' ', '');
87 | if (auxiliaryInfo) {
88 | neetsSpan.innerHTML = auxiliaryInfo;
89 | } else {
90 | neetsSpan.innerHTML = '免费';
91 | }
92 | neetsLi.appendChild(neetsMovie);
93 | neetsLi.appendChild(neetsSpan);
94 | neetsUl.appendChild(neetsLi);
95 | }
96 | var neetsLiMore = document.createElement('li');
97 | var neetsMovieMore = document.createElement('a');
98 | neetsMovieMore.setAttribute('href', rawUrl);
99 | neetsMovieMore.setAttribute('target', '_blank');
100 | neetsMovieMore.setAttribute('class', 'playBtn');
101 | neetsMovieMore.innerHTML = '发现更多>>>';
102 | neetsLiMore.appendChild(neetsMovieMore);
103 | neetsUl.appendChild(neetsLiMore);
104 | neetsDiv.appendChild(neetsUl);
105 | return neetsDiv;
106 | }
107 |
108 | function runDouban() {
109 | var h1 = document.getElementsByTagName('h1')[0];
110 | var movieName = h1.firstElementChild.innerText.split(' ')[0];
111 | var aside = document.getElementsByClassName('aside');
112 | if (aside) {
113 | search(movieName, aside[0]);
114 | }
115 |
116 | // douban book
117 | if (window.location.hostname === 'book.douban.com') {
118 | var menu = document.getElementsByClassName('nav-items');
119 | if (menu && menu[0]) {
120 | // show link only when mouse hover
121 | menu[0].addEventListener("mouseover", function () {
122 | var link = document.getElementById('neets-menu');
123 | if (link) {
124 | link.style['display'] = 'inline-block';
125 | }
126 | }, false);
127 | menu[0].addEventListener("mouseout", function () {
128 | var link = document.getElementById('neets-menu');
129 | if (link) {
130 | link.style['display'] = 'none';
131 | }
132 | }, false);
133 | }
134 | }
135 | }
136 |
137 | function insertCss() {
138 | // insert css
139 | var style = document.createElement('style');
140 | // webkit hack
141 | style.appendChild(document.createTextNode(''));
142 | // insert to head
143 | document.head.appendChild(style);
144 |
145 | // rules
146 | var rules = {
147 | '.buylink-price': {
148 | left: '130px',
149 | position: 'absolute',
150 | color: '#999'
151 | },
152 | '.gray_ad .report-error': {
153 | color: '#999',
154 | display: 'none',
155 | position: 'absolute',
156 | top: '10px',
157 | right: '10px',
158 | background: 'transparent'
159 | },
160 | '.gray_ad .report-error:hover': {
161 | display: 'inline'
162 | }
163 | };
164 | for (var ele in rules) {
165 | var rulesStr = ele + '{';
166 | for (var attr in rules[ele]) {
167 | rulesStr += attr + ': ' + rules[ele][attr] + ';';
168 | }
169 | rulesStr += '} ';
170 | style.sheet.insertRule(rulesStr, 0);
171 | }
172 | }
173 |
174 | insertCss();
175 | var host = window.location.hostname;
176 | if (host === 'movie.douban.com') {
177 | runDouban();
178 | }
179 | })();
180 |
--------------------------------------------------------------------------------