Skip to content

Commit

Permalink
support grab media files
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaozhuai committed Dec 30, 2019
1 parent 890d299 commit be42e93
Show file tree
Hide file tree
Showing 17 changed files with 1,949 additions and 1,248 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ pr and issue are welcome!
- [x] Drag downloaded file
- [x] Show `accept danger` dialog
- [x] Use `chrome.i18n`
- [ ] Grab media files in current tab
- [x] Grab media files in current tab
- [ ] Filter media files (filter by image size, audio duration, video duration...)
- [ ] more...
3 changes: 2 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
- [x] 文件拖拽
- [x] 显示`允许不安全内容`的弹窗
- [x] 统一使用`chrome.i18n`
- [ ] 抓取当前标签页内的媒体文件
- [x] 抓取当前标签页内的媒体文件
- [ ] 根据条件过滤媒体文件(通过图片大小,音频时长,视频时长等...)
- [ ] 更多...

## QQ群
Expand Down
6 changes: 6 additions & 0 deletions public/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"aboutPanelTitle": {
"message": "About"
},
"explorerPanelTitle": {
"message": "Explorer"
},
"openFile": {
"message": "Open file"
},
Expand Down Expand Up @@ -133,5 +136,8 @@
},
"fileRemoved": {
"message": "Removed"
},
"downloadSelectedFiles": {
"message": "Download selected"
}
}
6 changes: 6 additions & 0 deletions public/_locales/zh/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"aboutPanelTitle": {
"message": "关于"
},
"explorerPanelTitle": {
"message": "发现"
},
"openFile": {
"message": "打开文件"
},
Expand Down Expand Up @@ -133,5 +136,8 @@
},
"fileRemoved": {
"message": "已删除"
},
"downloadSelectedFiles": {
"message": "下载已选中"
}
}
6 changes: 6 additions & 0 deletions public/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"aboutPanelTitle": {
"message": "关于"
},
"explorerPanelTitle": {
"message": "发现"
},
"openFile": {
"message": "打开文件"
},
Expand Down Expand Up @@ -133,5 +136,8 @@
},
"fileRemoved": {
"message": "已删除"
},
"downloadSelectedFiles": {
"message": "下载已选中"
}
}
6 changes: 6 additions & 0 deletions public/_locales/zh_TW/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
"aboutPanelTitle": {
"message": "關於"
},
"explorerPanelTitle": {
"message": "發現"
},
"openFile": {
"message": "打開文件"
},
Expand Down Expand Up @@ -134,5 +137,8 @@
},
"fileRemoved": {
"message": "已刪除"
},
"downloadSelectedFiles": {
"message": "下載已選中"
}
}
97 changes: 97 additions & 0 deletions public/grabber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
function grabAllImgTags(doc) {
let list = [];
for (let el of Array.from(doc.getElementsByTagName('img'))) {
list.push({
type: 'image',
url: el.src,
});
}
return list;
}

function grabAllBackgroundImages(doc) {
let list = [];
const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i;
for (let el of Array.from(doc.querySelectorAll('*'))) {
let prop = window.getComputedStyle(el, null).getPropertyValue('background-image');
let match = srcChecker.exec(prop);
if (match) {
list.push({
type: 'image',
url: match[1],
});
}
}
return list;
}

function grabAllVideoTags(doc) {
let list = [];
for (let el of Array.from(doc.getElementsByTagName('video'))) {
list.push({
type: 'video',
thumb: el.poster,
url: el.src,
});
}
return list;
}

function grabAllAudioTags(doc) {
let list = [];
for (let el of Array.from(doc.getElementsByTagName('audio'))) {
list.push({
type: 'audio',
url: el.src,
});
}
return list;
}

function getAllDoc(doc = document) {
let docs = [doc];
for (let iframe of Array.from(doc.querySelectorAll('iframe'))) {
try {
docs = docs.concat(getAllDoc(iframe.contentDocument || iframe.contentWindow.document));
} catch (e) {

}
}
return docs;
}

function filterList(list) {
let newList = [];
let allUrl = [];
for (let item of list) {
if (item.url === '') {
continue;
}
if (allUrl.indexOf(item.url) >= 0) {
continue;
}
allUrl.push(item.url);
newList.push(item);
}
return newList;
}

function grabAll() {
let list = [];
let docs = getAllDoc();

for (let doc of docs) {
list = list
.concat(grabAllImgTags(doc))
.concat(grabAllBackgroundImages(doc))
.concat(grabAllVideoTags(doc))
.concat(grabAllAudioTags(doc));
}

// console.log(JSON.stringify(list, null, 4));
list = filterList(list);
// console.log(JSON.stringify(list, null, 4));
return list;
}

grabAll();
3 changes: 2 additions & 1 deletion public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"notifications",
"contextMenus",
"storage",
"unlimitedStorage"
"unlimitedStorage",
"activeTab"
],
"browser_action": {
"default_icon": "logo.png",
Expand Down
Binary file added src/assets/record.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/transparent_grid_background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions src/components/AudioPopover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<template>
<el-popover @show="onShow()" @hide="onHide()" trigger="hover">
<audio :src="audioSrc" autoplay/>
<img class="record" src="../assets/record.png" alt="record">
<div slot="reference">
<a class="audio-link" target="_blank" :href="src">{{src}}</a>
</div>
</el-popover>
</template>

<script>
export default {
name: 'AudioPopover',
components: {},
props: {
src: {
type: String,
default: '',
},
},
data() {
return {
audioSrc: '',
};
},
methods: {
onShow() {
this.audioSrc = this.src;
},
onHide() {
this.audioSrc = '';
}
},
};
</script>

<style scoped>
.audio-link {
display: inline-block !important;
vertical-align: bottom;
width: 100%;
text-decoration: none;
color: #333 !important;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>

<style>
.record {
width: 160px;
height: 160px;
animation: spin 2s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>
113 changes: 113 additions & 0 deletions src/components/ExplorerPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<template>
<div class="explorer-panel" v-loading="loading">
<el-table :data="tableData" @selection-change="handleSelectionChange" style="width: 100%;" height="482">
<el-table-column type="selection" width="42" align="center"/>
<el-table-column width="54" align="center" label="Type">
<i slot-scope="scope" :class="getIcon(scope.row.type)"></i>
</el-table-column>
<el-table-column prop="url" label="Url">
<template slot-scope="scope">
<img-popover v-if="scope.row.type === 'image'" :src="scope.row.url"/>
<video-popover v-else-if="scope.row.type === 'video'" :src="scope.row.url"/>
<audio-popover v-else-if="scope.row.type === 'audio'" :src="scope.row.url"/>
<a v-else class="item-link" target="_blank" :href="scope.row.url">{{scope.row.url}}</a>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-button :title="$tr('downloadSelectedFiles')" circle icon="el-icon-download"
@click="downloadSelectedFiles"/>
</div>
</div>
</template>

<script>
import ImgPopover from "./ImgPopover";
import VideoPopover from "./VideoPopover";
import AudioPopover from "./AudioPopover";
export default {
name: "ExplorerPanel",
components: {AudioPopover, VideoPopover, ImgPopover},
data() {
return {
loading: true,
tableData: [],
selectedData: [],
};
},
watch: {},
mounted() {
this.updateFiles();
},
methods: {
getIcon(type) {
switch (type) {
case 'image':
return 'el-icon-picture-outline';
case 'audio':
return 'el-icon-headset';
case 'video':
return 'el-icon-video-camera';
default:
return 'el-icon-document';
}
},
handleSelectionChange(val) {
this.selectedData = val;
},
downloadSelectedFiles() {
for (let item of this.selectedData) {
chrome.downloads.download({
url: item.url,
});
}
this.$emit('click-download');
},
async updateFiles() {
this.loading = true;
this.tableData = await this.grabAllMediaFiles();
this.selectedData = [];
this.loading = false;
},
grabAllMediaFiles() {
return new Promise((resolve, reject) => {
chrome.tabs.executeScript({
file: 'grabber.js'
}, result => {
if (result.length === 1) {
resolve(result[0]);
} else {
console.error('grabAllMediaFiles failed!');
resolve([]);
}
});
});
}
}
}
</script>

<style scoped>
.item-link {
text-decoration: none;
color: #333 !important;
}
.explorer-panel > .footer {
width: 100%;
height: 40px;
padding: 5px 12px;
}
.explorer-panel > .footer > * + * {
margin-left: 10px;
}
</style>

<style>
.el-table .cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
Loading

0 comments on commit be42e93

Please sign in to comment.