- // ==UserScript==
- // @name Pixiv Collection Plus
- // @namespace niaier pixiv collection
- // @license MIT
- // @version 0.1
- // @description pixiv收藏拓展
- // @author niaier
- // @match *://www.pixiv.net/*
- // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
- // @grant GM_addStyle
- // @grant GM_getResourceText
- // @grant GM_xmlhttpRequest
- // @grant GM_download
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant GM_setClipboard
- // @grant unsafeWindow
- // @grant window.close
- // @grant window.focus
- // @grant window.onurlchange
- // @require https://code.jquery.com/jquery-3.6.0.min.js
- // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js
- // @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.3/cpexcel.js
- // @require https://cdnjs.cloudflare.com/ajax/libs/dexie/3.2.1/dexie.min.js
- // @resource css https://unpkg.com/element-ui/lib/theme-chalk/index.css
- // @require https://cdn.jsdelivr.net/npm/vue@2.6.14
- // @require https://unpkg.com/element-ui/lib/index.js
- // @require https://cdn.jsdelivr.net/npm/echarts@5.2.2/dist/echarts.min.js
- // @connect *
- // ==/UserScript==
-
- window.onload = function () {
- // 替换element字体源
- const styleText = GM_getResourceText("css").replace('fonts/element-icons.woff', 'https://unpkg.com/element-ui@2.13.0/lib/theme-chalk/fonts/element-icons.woff').replace('fonts/element-icons.ttf', 'https://unpkg.com/element-ui@2.13.0/lib/theme-chalk/fonts/element-icons.ttf')
- // GM_addStyle(GM_getResourceText("css"));
- GM_addStyle(styleText);
-
- class Database extends Dexie {
- constructor() {
- super('pixiv');
- this.version('1.0').stores({
- production: '++id,&url,title,custom_category,tag',
- collection: '++id,url,title,custom_category,tag,collection_list,collection_list_id',
- collection_class_list: '++id,list_name'
- });
-
- this.collection = this.table('collection');
- this.collectionClassList = this.table('collection_class_list');
- }
- // 当前有关收藏
- async getCurCollection (url) {
- let curCollection = []
- curCollection = await this.collection.where('url').equals(url).toArray()
- return curCollection
- }
- // 添加收藏
- async addToCollection (data) {
- return await this.collection.add(data)
- }
- // 删除收藏
- async deleteCollection (id, url) {
- console.log(id, url);
- return await this.collection
- .where({ 'collection_list_id': id, url }).delete()
- }
- // 获取收藏列表
- async getCollectionList () {
- let collectionClassList = []
- collectionClassList = await this.collection_class_list.orderBy('id').toArray();
- return collectionClassList
- }
- // 添加收藏列表
- async addCollectionList (data) {
- return await this.collection_class_list.add(data)
- }
- //删除收藏列表
- async deleteCollectionList (id) {
- await this.collection_class_list.where('id').equals(id).delete()
- await this.collection.where('collection_list_id').equals(id).delete()
- return
- }
- //获取收藏列表下的藏品
- async getCollectionListContent (collection_list_id) {
- // 参数 收藏列表id collection_list_id
- let collectionListContent = []
- collectionListContent = await this.collection.where('collection_list_id').equals(collection_list_id).toArray()
- return collectionListContent
- }
- // 获取自定义标签
- async getCustomCategory (url) {
- let custom_category = []
- const production = await this.production.where('url').equals(url).toArray()
- custom_category = production[0] ? production[0].custom_category : []
- console.log(custom_category);
- return custom_category
- }
- // 添加自定义标签
- // 添加作品
- async putProduction (data) {
- return await this.production.put(data)
- }
- //获取作品
- async getProduction (url) {
- let arr = []
- arr = await this.production.where('url').equals(url).toArray()
- return arr[0]
- }
- // 修改自定义标签
- async putCustomCategory (url, custom_category) {
- console.log(url, custom_category);
- await this.production.where('url').equals(url).modify({
- custom_category
- })
- }
- async getAllData () {
- const production = await this.production.toArray()
- const collection = await this.collection.toArray()
- const collection_class_list = await this.collection_class_list.toArray()
- return { production, collection, collection_class_list }
-
- }
- async importAllData (data) {
- // 先清空
- // await this.production.delete()
- // await this.collection.delete()
- // await this.collection_class_list.delete()
-
- await this.production.bulkPut(data.production)
- await this.collection.bulkPut(data.collection)
- await this.collection_class_list.bulkPut(data.collection_class_list)
- }
-
-
- }
-
-
-
-
-
-
-
-
- const viewCollection =
- `
- <div id="viewCollection">
- <el-button type="primary" size="small" :style="{
- 'margin-left': '10px'
- }" @click="showCollection">查看收藏</el-button>
-
-
- <el-dialog title="查看收藏列表" :visible.sync="collectionVisible" width="60%" center append-to-body :style="{
- height: '80%',
- }">
- <el-container>
- <el-aside width="200px">
- <h5>收藏列表</h5>
- <el-menu default-active="0" class="el-menu-vertical-demo">
- <el-menu-item :index="index" :key="item.id" v-for="(item, index) in collectionList">
- <i class="el-icon-menu"></i>
- <span slot="title" @click="getCollectionListContent(item)">{{ item.list_name }}</span>
- </el-menu-item>
- </el-menu>
- </el-aside>
- <el-main>
- <div>
- <div
- :style="{
- 'margin-bottom': '10px'
- }"
- >
- <h5>收藏展示</h5>
- <el-button type="primary" @click="exportJson" size="small">导出json</el-button>
-
- <input type="file" name="file" id="importJson" v-show="false" @change="handleImport">
- <el-button size="small" type="primary" @click="importJson" :style="{
- 'margin-left': '10px',
- }">导入Json</el-button>
- </div>
- <el-row :gutter="10">
- <el-col :span="8" :key="item.id" v-for="item in collectionListContent">
- <div :style="{ height: 250 }">
- <div class="pic" :style="{ 'text-align': 'center' }">
- <img :src="item.preview_url" alt="" height="184" />
- </div>
- <div class="title" :style="{
- 'display':'flex',
- 'justify-content':'center'
- }">
- <h5 :style="{width:'130px'}">
- <el-link :href="item.url" target="_blank">
- {{ item.title }}
- </el-link>
- </h5>
- </div>
- </el-col>
- </el-row>
- </div>
- </el-main>
- </el-container>
- </el-dialog>
- </div>
- `
- const addCollection =
- ` <div id="addCollection">
- <el-button
- type="primary"
- size="small"
- @click="showCollectionList"
- :style="{
- 'margin-right': '10px'
- }"
- >
- 添加到收藏</el-button
- >
- <el-dialog
- title="收藏列表"
- :visible.sync="collectionListVisible"
- width="30%"
- center
- append-to-body
- >
- <div class="currentTag">
- <h5
- :style="{
- 'margin-bottom': '10px',
- }"
- >
- 当前标签:
- </h5>
- <span>
- <el-tag
- v-for="item in tag"
- :key="item"
- type="info"
- size="mimi"
- :style="{
- 'margin-left': '10px',
- 'margin-bottom': '10px',
- }"
- >
- {{ item.originTag + " | " + item.translatedTag }}
- </el-tag>
- </span>
- </div>
- <div
- class="customTag"
- :style="{
- 'margin-top': '10px',
- 'margin-bottom': '10px',
- }"
- >
- <h5
- :style="{
- 'margin-bottom': '10px',
- }"
- >
- 自定义标签:
- </h5>
-
- <span>
- <el-tag
- :key="item"
- size="mimi"
- v-for="item in custom_category"
- closable
- :disable-transitions="false"
- @close="deleteCustomCategory(item)"
- :style="{
- 'margin-left': '10px',
- 'margin-button': '10px',
- }"
- >
- {{ item.originTag + " | " + item.translatedTag }}
- </el-tag>
- <el-input
- class="input-new-tag"
- v-if="customCategoryInputVisible"
- v-model="selfCategory"
- ref="saveTagInput"
- size="small"
- @keyup.enter.native="addSelfCategory"
- >
- </el-input>
- <el-button
- v-else
- class="button-new-tag"
- size="small"
- @click="showSelfCategoryInput"
- >+ New Tag</el-button
- >
- </span>
- </div>
-
- <el-input
- placeholder="新建收藏列表"
- v-model="inputListName"
- class="input-with-select"
- :style="{
- 'margin-top': '10px',
- 'margin-button': '10px',
- }"
- >
- <el-button
- slot="append"
- @click="addCollectionList"
- size="small"
- type="primary"
- icon="el-icon-plus"
- ></el-button>
- </el-input>
-
- <div class="collectionList">
- <el-row>
- <el-col
- :span="24"
- v-for="(item, index) in collectionList"
- :key="index"
- :style="{
- 'display':'flex',
- 'justify-content':'space-between',
- 'margin-top':'10px'
- }"
- >
- <el-checkbox
- v-model="item.checked"
- @change="changeChecked(index, item)"
- >{{ item.list_name }}</el-checkbox
- >
- <i
- class="el-icon-delete"
- @click="deleteCollectionList(item)"
- :style="{
- cursor:'pointer'
- }"
- ></i>
- </el-col>
- </el-row>
- </div>
- <span slot="footer" class="dialog-footer">
- <el-button @click="collectionListVisible = false"
- >取 消</el-button
- >
- <el-button
- type="primary"
- @click="collectionListVisible = false"
- >确 定</el-button
- >
- </span>
- </el-dialog>
- </div>`
-
- $('#root > div:nth-child(2) > div.sc-12xjnzy-0.dIGjtZ > div:nth-child(1) > div:nth-child(1) > div > div.sc-4nj1pr-2.fDmigA').append(viewCollection)
- $('#root > div:nth-child(2) > div.sc-1nr368f-0.beQeCv > div > div.sc-1nr368f-3.dkdRNk > main > section > div.sc-171jvz-0.gcrJTU > div > div.sc-rsntqo-0.fPeueM > div > div.sc-ye57th-1.lbzRfC > section').append(addCollection)
- new Vue({
- el: '#viewCollection',
- data: () => ({
- collectionVisible: false,
- collectionList: [],
- collectionListContent: []
- }),
- created () {
- this.db = new Database()
- },
- methods: {
- showCollection () {
- this.collectionVisible = true
- this.getCollectionList()
- },
- async getCollectionList () {
- const collectionList = await this.db.getCollectionList()
- this.collectionList = collectionList
- },
- async getCollectionListContent (item) {
- const collection_list_id = item.id
-
- const collectionListContent = await this.db.getCollectionListContent(collection_list_id)
- this.collectionListContent = collectionListContent
- console.log('collectionListContent', collectionListContent)
- },
- // 导出
- async exportJson () {
- const curDate = moment().format('YYYY_MM_hh_mm_ss');
- const jsonObj = await this.db.getAllData()
- const data = JSON.stringify(jsonObj)
- let blob = new Blob([data], { type: 'text/json' })
- let a = document.createElement('a')
- a.download = `pixiv收藏数据${curDate}.json`
- a.href = window.URL.createObjectURL(blob)
- document.body.appendChild(a);
- a.click()
- document.body.removeChild(a);
- },
- //导入
- importJson () {
- const input = document.querySelector('#importJson')
- input.click()
- },
- handleImport () {
- const that = this
- const selectedFile = document.querySelector('#importJson').files[0]
- const reader = new FileReader()
- reader.readAsText(selectedFile)
- let JsonObj = {}
- reader.onload = function () {
- JsonObj = JSON.parse(this.result)
- that.db.importAllData(JsonObj)
- }
-
- }
- }
- })
-
- new Vue({
- el: '#addCollection',
- data: () => ({
- collectionListVisible: false,
- inputListName: '',
- defaultChecked: false,
- collectionList: [],
- db: {},
- url: window.location.href,
- title: '',
- tag: [],
- selfCategory: '',
- custom_category: [],
- customCategoryInputVisible: false,
- production: {},
- previewUrl: ''
- }),
- created () {
- this.db = new Database()
- },
- mounted () {
- this.getTitle()
- this.getTag()
- this.initData()
- this.getPreviewUrl()
- },
- methods: {
- initData () {
- this.getProduction()
- this.getCollectionList()
- this.getCurCollection()
- },
- showCollectionList () {
- this.collectionListVisible = true
- this.initData()
- },
- getTitle () {
- const title = document.querySelector("#root > div:nth-child(2) > div.sc-1nr368f-0.beQeCv > div > div.sc-1nr368f-3.dkdRNk > main > section > div.sc-171jvz-0.gcrJTU > div > figcaption > div > div > h1").innerText
- this.title = title
- console.log(this.title);
- },
- getTag () {
- const tagList = []
- const liList = document.querySelectorAll('.sc-pj1a4x-0 .sc-h7k48h-0.lhUcKZ')
- liList.forEach(item => {
- originTag = item.querySelector('.gtm-new-work-tag-event-click').innerText
- translatedTag = item.querySelector('.gtm-new-work-translate-tag-event-click') ? item.querySelector('.gtm-new-work-translate-tag-event-click').innerText : ''
- const obj = {
- originTag,
- translatedTag
- }
- tagList.push(obj)
-
- })
- this.tag = tagList
- console.log(this.tag);
-
- },
- getCustomCategory () {
- console.log("this.production", this.production);
- this.custom_category = this.production ? this.production.custom_category : []
- },
- getPreviewUrl () {
- this.previewUrl = document.querySelector("a.gtm-expand-full-size-illust").href
- },
- async putCustomCategory () {
- console.log('custom_category', this.custom_category);
- await this.db.putCustomCategory(window.location.href, this.custom_category)
- },
- showSelfCategoryInput () {
- this.customCategoryInputVisible = true
- },
- addSelfCategory () {
- const categoryList = this.selfCategory.split("|")
- let originTag = ''
- let translatedTag = ''
- if (categoryList.length > 1) {
- originTag = categoryList[0]
- translatedTag = categoryList[1]
- } else if (categoryList.length == 1) {
- originTag = categoryList[0]
- translatedTag = ''
- }
- const obj = {
- originTag,
- translatedTag
- }
- this.custom_category.push(obj)
- this.custom_category = Array.from(new Set(this.custom_category))
- this.putCustomCategory()
- this.customCategoryInputVisible = false
- this.initData()
-
- },
-
- deleteCustomCategory (tag) {
- this.custom_category.splice(this.custom_category.indexOf(tag), 1);
- this.putCustomCategory()
- this.initData()
- },
-
- changeChecked (index, item) {
- if (item.checked == true) {
- this.addToCollection(item)
- } else {
- this.deleteCollection(item.id, window.location.href)
- }
- },
- async getProduction () {
- this.production = await this.db.getProduction(window.location.href)
- this.getCustomCategory()
- this.production = this.production || {}
- },
- async putProduction () {
-
- const data = {
- id: this.production.id,
- title: this.title,
- url: window.location.href,
- tag: this.tag,
- custom_category: this.custom_category,
- preview_url: this.previewUrl
- }
- console.log('putProduction', data);
- await this.db.putProduction(data)
- },
-
- async addToCollection (item) {
- const data = {
- title: this.title,
- url: window.location.href,
- tag: this.tag,
- custom_category: this.custom_category,
- collection_list: item.list_name,
- collection_list_id: item.id,
- preview_url: this.previewUrl
- }
- await this.db.addToCollection(data);
- this.putProduction()
- this.getCurCollection()
- },
- async deleteCollection (id, url) {
- await this.db.deleteCollection(id, url)
- this.getCurCollection()
- },
- // 获取当前作品相关的收藏记录
- async getCurCollection () {
- const url = window.location.href
- const curCollection = await this.db.getCurCollection(url)
- this.curCollection = curCollection
- this.handleCurChecked()
- },
- async getCollectionList () {
- const collectionList = await this.db.getCollectionList()
- this.collectionList = collectionList
- },
- // 添加列表
- async addCollectionList () {
- const listName = this.inputListName
- const data = {
- list_name: listName
- }
- await this.db.addCollectionList(data)
- this.getCollectionList()
- },
- //删除列表
- async deleteCollectionList (item) {
- console.log('deleteCollectionList', item.id);
- this.db.deleteCollectionList(item.id)
- this.initData()
- this.getCurCollection()
- },
- // 处理收藏列表的显示效果
- handleCurChecked () {
- const arr = this.collectionList.map(item1 => {
- this.curCollection.forEach(item2 => {
- if (item1.id == item2.collection_list_id) {
- item1.checked = true
- }
- })
- return item1
- })
- console.log(arr);
- this.collectionList = arr
- },
-
- }
- })
- }