drag thumbs and deviations to yur favourites/collections
当前为
// ==UserScript==
// @name dA_DragnFav
// @namespace phi.pf-control.de/userscripts/dA_DragnFav/dA_DragnFav.user.js
// @version 1.2
// @description drag thumbs and deviations to yur favourites/collections
// @author Dediggefedde
// @match https://www.deviantart.com/*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @require http://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
// @grant GM_addStyle
// @grant GM.xmlHttpRequest
// @grant GM.setValue
// @grant GM.getValue
// ==/UserScript==
/* globals $*/
/* jshint esnext:true */
// faving informations:
// POST https://www.deviantart.com/_napi/shared_api/collections/collect
// {"itemid":864977862,"folderids":[1468881,48232885],"csrf_token":"Jt3u9HHt4hGtMxG7.qluh26.7-qAIhS-bmbIhMbgks-rKcuE_j1y6EsqMJyonDrrjsE"}
(function() {
'use strict';
//# temporary variables
let grIDs = [];
let settingmode=false;
let groupOrder=[];
let hiddengroups=[];
let headerfilled=false;
//# resources
//hook copied from deviantart svg
let imgHook='<svg width="50" height="50" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"><path d="M1.237 6.187L0 4.95l1.237-1.238L2.475 4.95l3.712-3.713 1.238 1.238-4.95 4.95-1.238-1.238z" fill-rule="evenodd"></path></svg>';
//imgGear copied from inkscape "render gear", slightly adjusted
let imgGear='<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 20.444057 20.232336" > <g transform="translate(-15.480352,-5.6695418)"> <g transform="matrix(0.26458333,0,0,0.26458333,25.702381,15.78571)" style="fill:#000000"> <path style="fill:#000000;stroke:#000000;stroke-width:1" d="m 28.46196,-3.25861 4.23919,-0.48535 0.51123,0.00182 4.92206,1.5536 v 4.37708 l -4.92206,1.5536 -0.51123,0.00182 -4.23919,-0.48535 -1.40476,6.15466 4.02996,1.40204 0.45982,0.22345 3.76053,3.53535 -1.89914,3.94361 -5.1087,-0.73586 -0.4614,-0.22017 -3.60879,-2.2766 -3.93605,4.93565 3.02255,3.01173 0.31732,0.40083 1.8542,4.81687 -3.42214,2.72907 -4.2835,-2.87957 -0.32017,-0.39856 -2.26364,-3.61694 -5.68776,2.73908 1.41649,4.0249 0.11198,0.49883 -0.41938,5.14435 -4.26734,0.97399 -2.6099,-4.45294 -0.11554,-0.49801 -0.47013,-4.2409 h -6.31294 l -0.47013,4.2409 -0.11554,0.49801 -2.6099,4.45294 -4.26734,-0.97399 -0.41938,-5.14435 0.11198,-0.49883 1.41649,-4.0249 -5.68776,-2.73908 -2.26364,3.61694 -0.32017,0.39856 -4.2835,2.87957 -3.42214,-2.72907 1.8542,-4.81687 0.31732,-0.40083 3.02255,-3.01173 -3.93605,-4.93565 -3.60879,2.2766 -0.4614,0.22017 -5.1087,0.73586 -1.89914,-3.94361 3.76053,-3.53535 0.45982,-0.22345 4.02996,-1.40204 -1.40476,-6.15466 -4.23919,0.48535 -0.51123,-0.00182 -4.92206,-1.5536 v -4.37708 l 4.92206,-1.5536 0.51123,-0.00182 4.23919,0.48535 1.40476,-6.15466 -4.02996,-1.40204 -0.45982,-0.22345 -3.76053,-3.53535 1.89914,-3.94361 5.1087,0.73586 0.4614,0.22017 3.60879,2.2766 3.93605,-4.93565 -3.02255,-3.01173 -0.31732,-0.40083 -1.8542,-4.81687 3.42214,-2.72907 4.2835,2.87957 0.32017,0.39856 2.26364,3.61694 5.68776,-2.73908 -1.41649,-4.0249 -0.11198,-0.49883 0.41938,-5.14435 4.26734,-0.97399 2.6099,4.45294 0.11554,0.49801 0.47013,4.2409 h 6.31294 l 0.47013,-4.2409 0.11554,-0.49801 2.6099,-4.45294 4.26734,0.97399 0.41938,5.14435 -0.11198,0.49883 -1.41649,4.0249 5.68776,2.73908 2.26364,-3.61694 0.32017,-0.39856 4.2835,-2.87957 3.42214,2.72907 -1.8542,4.81687 -0.31732,0.40083 -3.02255,3.01173 3.93605,4.93565 3.60879,-2.2766 0.4614,-0.22017 5.1087,-0.73586 1.89914,3.94361 -3.76053,3.53535 -0.45982,0.22345 -4.02996,1.40204 z" /> <circle style="fill:#ffffff;stroke:#000000;stroke-width:1" cx="0" cy="0" r="15" /> </g> </g> </svg>';
//CSS styling
//"#dA_DragnFav_header div[folderId] * {pointer-events: none;}
GM_addStyle(`
#dA_DragnFav_header {color:var(--L8);background-color: #8fac85cc;z-index: 77;position: fixed;width: 100%;border: 2px ridge white;
display: none;padding: 20px;justify-content: center;align-items: center;flex-wrap: wrap;box-sizing: border-box;}
#dA_DragnFav_header div[folderId] {padding: 15px;border-radius: 5px;background-color: #ffffdd;border: 1px solid black;margin: 10px;
display:flex;align-items: center;flex-direction: column;position: relative;overflow:clip;}
#dA_DragnFav_header div[folderId] img {height:50px;max-width: 100px; overflow: hidden;text-overflow: ellipsis;font-size: smaller;}
#dA_DragnFav_header div.dA_DragnFav_sets{position:absolute;top:10px;right:10px;cursor:pointer;}
#dA_DragnFav_header div.dA_DragnFav_markhide{background-color:#a22;}
div.dA_DragnFav_right{right:0}
div.dA_DragnFav_groupTitle{display:inline-block;}
div.dA_DragnFav_left{left:0}
div.dA_DragnFav_over{z-index:3;position: absolute;top: 0;width: 50%;height: 100%;
background-color: #b9d9b1;display: flex;align-items: center;justify-content: center;opacity:0;}
div.dA_DragnFav_over p{pointer-events: none;}
div.dA_DragnFav_inside {position:absolute;z-index:2;left:0;width:100%;top:0;height:100%;display:flex;align-items: center;justify-content: center;visibility:hidden}
div.dA_DragnFav_inside svg {fill:green;}
#dA_DragnFav_drowDown{color:var(--L8);max-height:350px;position:absolute;z-index:99;top:0;left:0;border:1px solid green;
overflow-y:scroll;border-radius:5px;background: linear-gradient(90deg,var(--L19),var(--L3),var(--L19));}
#dA_DragnFav_drowDown li{height:50px;background-color:var(--L19);position: relative;overflow:hidden;margin:2px 0;}
#dA_DragnFav_drowDown li:hover{background-color:var(--L2)}
#dA_DragnFav_drowDown img{overflow: hidden;text-overflow: ellipsis;font-size: smaller;max-width: 100px;height: 100%;}
#dA_DragnFav_drowDown div.dA_DragnFav_wrapImg{width: 100px; overflow: hidden;text-overflow: ellipsis;font-size: smaller;
display:inline-block;vertical-align:middle;position: relative;height: 100%;text-align: center;}
#dA_DragnFav_drowDown div.dA_DragnFav_groupTitle{margin:0 15px}
`.replace(/\s\s+/g,''));
//# https requests
//gets your currently available collections. returns promise with json response on success. response or parse error on error
//assumes <21 collections
function getCollections(offset=0) {
return new Promise(function(resolve, reject) {
GM.xmlHttpRequest({
method: "GET",
url: "https://www.deviantart.com/_napi/shared_api/gallection/folders?type=collection&offset="+offset+"&limit=20",
headers: {
"accept": 'application/json, text/plain, */*',
"content-type": 'application/json;charset=UTF-8'
},
onerror: function(response) {
console.log("error:", response);
reject(response);
},
onload: async function(response) {
let dat;
try {
dat = JSON.parse(response.responseText);
if(dat.hasMore){
getCollections(dat.nextOffset).then(nret=>{
dat.results=dat.results.concat(nret.results);
resolve(dat);
return;
});
}else{
resolve(dat);
}
} catch (e) {
reject(e);
}
}
});
});
}
//get list of collection ids, this deviation id is inside already
//returns promise with json response on success. response or parse error on error
function inCollections(id) {
return new Promise(function(resolve, reject) {
GM.xmlHttpRequest({
method: "GET",
url: "https://www.deviantart.com/_napi/shared_api/collections/collections_for_deviation?deviationid=" + id,
headers: {
"accept": 'application/json, text/plain, */*',
"content-type": 'application/json;charset=UTF-8'
},
onerror: function(response) {
console.log("error:", response);
reject(response);
},
onload: async function(response) {
let dat;
try {
dat = JSON.parse(response.responseText);
} catch (e) {
reject(e);
}
resolve(dat);
}
});
});
}
//sets the collection of the deviation with this id to the array cols (folder ids).
//searches for validate_token on current page
function setCollection(id, cols) {
let token = $("input[name=validate_token]").val();
let dat = {
"itemid": id,
"folderids": cols,
"csrf_token": token
};
return new Promise(function(resolve, reject) {
GM.xmlHttpRequest({
method: "POST",
url: "https://www.deviantart.com/_napi/shared_api/collections/collect",
headers: {
"accept": 'application/json, text/plain, */*',
"content-type": 'application/json;charset=UTF-8'
},
dataType: 'json',
data: JSON.stringify(dat),
onerror: function(response) {
console.log("error:", response);
reject(response);
},
onload: async function(response) {
let dat;
try {
dat = JSON.parse(response.responseText); //returns {success:true}
} catch (e) {
reject(e);
}
resolve(dat);
}
});
});
}
//# event listener
//when items are dragged onto the bar
function itemDroppedOnCol(event,add=true,mid=0) {
let id=mid;
if(mid==0)id= event.originalEvent.dataTransfer.getData('id');
let fEl = $(event.target).closest("[folderId]");
let fId = parseInt(fEl.attr("folderId"));
if(!add)grIDs=[];
if (!grIDs.includes(fId)) {
grIDs.push(fId);
setCollection(id, grIDs).then(ret => {
fEl.find(".dA_DragnFav_inside").css("visibility", "visible");
}).then(()=>{
markCollections(id);
});
// fEl.find(".dA_DragnFav_inside").css("visibility", "visible");
}
}
function leaveSettingMode(){
settingmode=false;
$("#dA_DragnFav_header div.dA_DragnFav_markhide").css("display","none");
$("#dA_DragnFav_header div.dA_DragnFav_setDescr").remove();
$("#dA_DragnFav_header").fadeOut();
}
function enterSettingMode(){
settingmode=true;
//show hidden
$("#dA_DragnFav_header div.dA_DragnFav_markhide").css("display","block");
//make sortable
$("#dA_DragnFav_header").sortable({
helper: 'clone',
forceHelperSize :true,
forcePlaceholderSize :true,
placeholder: "ui-state-highlight",
items: 'div.dA_DragnFav_group',
cursor: 'move',
update: function (event, ui) {
let colOrder = $(this).sortable('toArray', {attribute: 'folderId'});
GM.setValue("groupOrder", JSON.stringify(colOrder));
}
}).prepend("<div class='dA_DragnFav_setDescr' style='width:100%'>Drag items to rearange them. Click an item to hide/show it. Click the gear to leave the settings mode.</div>");
}
//# initialization, reruns periodically for dynamic site building
//insert fav-header
function fillHeader(id) {
return (new Promise(function(resolve, reject) {
if(headerfilled){
resolve(id);
return;
}
getCollections(0).then((ret) => {
headerfilled=true;
let tex = "";
let contextTex="";
ret.results.forEach((el) => {
let thumb="";
if (el.thumb && el.thumb.coverImage && el.thumb.coverImage.media && el.thumb.coverImage.media.types && el.thumb.coverImage.media.prettyName && el.thumb.coverImage.media.token) { //optional chaining breaks tampermonkey syntax highlight...
thumb +=`${el.thumb.coverImage.media.baseUri}/${el.thumb.coverImage.media.types[0].c.replace("<prettyName>", el.thumb.coverImage.media.prettyName)}?token=${el.thumb.coverImage.media.token[0]}`;
} else if(el.thumb && el.thumb.media && el.thumb.media.baseUri && el.thumb.media.types && el.thumb.media.prettyName && el.thumb.media.token) {
thumb +=`${el.thumb.media.baseUri}/${el.thumb.media.types[0].c.replace("<prettyName>", el.thumb.media.prettyName)}?token=${el.thumb.media.token[0]}`;
}
let thTitl="no thumb";
if(el.thumb){
thTitl=el.thumb.title;
}
tex += `
<div class='dA_DragnFav_group ${hiddengroups.includes(el.folderId)?"dA_DragnFav_markhide":""}' folderId='${el.folderId}' ${hiddengroups.includes(el.folderId)?"style='display:none;'":""}>
<img src='${thumb}' alt='${thTitl}' title='${thTitl}'/>
<div class='dA_DragnFav_groupTitle'>${el.name}</div>
<div class='dA_DragnFav_inside'>${imgHook}</div>
<div class='dA_DragnFav_over dA_DragnFav_left'><p>Add</p></div>
<div class='dA_DragnFav_over dA_DragnFav_right'><p>Move</p></div>
</div>
`.replace(/\s\s+/g, '');
contextTex+=`<li class='dA_DragnFav_group ${hiddengroups.includes(el.folderId)?"dA_DragnFav_markhide":""}' folderId='${el.folderId}' ${hiddengroups.includes(el.folderId)?"style='display:none;'":""}>
<div class='dA_DragnFav_wrapImg'><img src='${thumb}' alt='${thTitl}' title='${thTitl}'/></div>
<div class='dA_DragnFav_groupTitle'>${el.name}</div>
<div class='dA_DragnFav_inside'>${imgHook}</div>
<div class='dA_DragnFav_over dA_DragnFav_left'><p>Add</p></div>
<div class='dA_DragnFav_over dA_DragnFav_right'><p>Move</p></div>
</li>`.replace(/\s\s+/g, '');
});
let header= $("#dA_DragnFav_header");
header.html(tex).append(`<div class='dA_DragnFav_sets'>${imgGear}</div>`);
let context= $("#dA_DragnFav_drowDown").html(contextTex);
// if (groupOrder.length > 0) {
$.each(groupOrder, function (i, folderid) {
let $target = header.find(`[folderid='${folderid}']`);
$target.appendTo(header); // or prependTo for reverse
});
// }
$("#dA_DragnFav_header div.dA_DragnFav_group").click(function(ev){
if(settingmode && !$(this).hasClass("noClick")){ //hide toggle click in setting-mode
let fid=parseInt($(this).attr("folderId"));
let fhidInd=hiddengroups.indexOf(fid);
if(fhidInd>-1){
hiddengroups.splice(fhidInd,1);
$(this).removeClass("dA_DragnFav_markhide");
}else{
hiddengroups.push(fid);
$(this).addClass("dA_DragnFav_markhide");
}
GM.setValue("hiddengroups",JSON.stringify(hiddengroups));
}
});
//fav-header drag receivable
$("#dA_DragnFav_header div.dA_DragnFav_over").on('dragover', false).on("dragenter", function(ev) {
ev.preventDefault();
ev.stopPropagation();
$(ev.target).css("opacity", "0.5");
}).on("dragleave", function(ev) {
ev.preventDefault();
ev.stopPropagation();
$(ev.target).css("opacity", "0");
}).on("drop", function(ev) {
ev.preventDefault();
ev.stopPropagation();
$(ev.target).css("opacity", "0");
itemDroppedOnCol(ev,$(ev.target).hasClass("dA_DragnFav_left"));
});
$("#dA_DragnFav_drowDown div.dA_DragnFav_over").on('mouseover', false).on("mouseenter", function(ev) {
ev.preventDefault();
ev.stopPropagation();
$(ev.target).css("opacity", "0.5");
}).on("mouseleave", function(ev) {
ev.preventDefault();
ev.stopPropagation();
$(ev.target).css("opacity", "0");
}).on("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
$(ev.target).css("opacity", "0");
let idMat=location.href.match(/\/art\/[^\/]*?(\d+)/i);
let id;
if(idMat==null){
id = $("#dA_DragnFav_drowDown").attr("ImgId");
}else if(idMat.length>0){
id = idMat[1]; //$("meta[property='og:url']").attr("content").match(/\d+$/i)[0];
}
itemDroppedOnCol(ev,$(ev.target).hasClass("dA_DragnFav_left"),id);
});
//settings open on drag, close on click
$("#dA_DragnFav_header div.dA_DragnFav_sets").on('dragover', false).on("dragenter", function(ev) {
ev.preventDefault();
ev.stopPropagation();
}).on("dragleave", function(ev) {
ev.preventDefault();
ev.stopPropagation();
}).on("drop", function(ev) {
ev.preventDefault();
ev.stopPropagation();
enterSettingMode();
}).click(function(ev){
leaveSettingMode();
});
resolve(id);
return;
});
})).then(markCollections);
}
function markCollections(id){
$(".dA_DragnFav_inside").css("visibility", "");
$(".dA_DragnFav_group").css("background-color", "");
// grIDs = [];
inCollections(id).then(ret => {
if(!ret.collectionIds){
console.log("error checking collections:",ret,id);
}
ret.collectionIds.forEach(el => {
$("[folderId=" + el + "]").find(".dA_DragnFav_inside").css("visibility", "visible");
$("[folderId=" + el + "]").closest(".dA_DragnFav_group").css("background-color", "rgb(180, 255, 200)");
});
// grIDs = ret.collectionIds;
});
}
function dragEnd(){
if(!settingmode){
$("#dA_DragnFav_header").fadeOut();
}
}
function dragStart(ev) {
$("#dA_DragnFav_header").css("display", "flex");
$("div.dA_DragnFav_over").css("opacity", "0");
let drEl=$(this).closest("a[href]");
let mode = $(this).attr("dA_DragnFav");
let id;
if (mode == 1 && drEl.attr("href")) {
id = drEl.attr("href").match(/\d+$/i)[0];
} else if (mode == 2){
let idMat=location.href.match(/\/art\/[^\/]*?(\d+)/i);
if(idMat.length>0){
id = idMat[1]; //$("meta[property='og:url']").attr("content").match(/\d+$/i)[0];
}
}
if(!id){
console.log("error: ID can not be fetched",mode, drEl, $(this),$(ev.target),$(ev.target).attr("href"),location.href.match(/\/art\/[^\/]*?(\d+)/i));
}
ev.originalEvent.dataTransfer.setData('id', id);
fillHeader(id);
}
//make deviations draggable, passing link with ID
function makeDraggable() {
let els = $("[data-hook='deviation_link']").not("[dA_DragnFav]").attr("dA_DragnFav", 1).attr("draggable", "true");
els.on("dragstart", dragStart).on("dragend", dragEnd);
els = $("[data-hook='art_stage'] img").not("[dA_DragnFav]").attr("dA_DragnFav", 2).attr("draggable", "true");
els.on("dragstart", dragStart).on("dragend", dragEnd);
els=$("button[data-hook=\"fave_button\"]").not("[dA_DragnFav]").attr("dA_DragnFav", 1);
els.contextmenu(function(e) {
e.preventDefault();
let idMat=location.href.match(/\/art\/[^\/]*?(\d+)/i);
let id;
if(idMat==null){
id = $(this).closest('section').attr("url").match(/\d+$/i)[0];
}else if(idMat.length>0){
id = idMat[1]; //$("meta[property='og:url']").attr("content").match(/\d+$/i)[0];
}
fillHeader(id);
$('#dA_DragnFav_drowDown').attr("ImgId",id).css({'top': e.pageY,'left':e.pageX}).show();
});
if(els.length>0){
let plusImg= document.createElementNS('http://www.w3.org/2000/svg', "path");
plusImg.setAttribute("stroke","#0A0");
plusImg.setAttribute("stroke-width","4");
plusImg.setAttribute("stroke-opacity","0.8");
plusImg.setAttribute("d","M12 18H24M18 12V24");
els.find("svg").append(plusImg);
}
}
//runs every interval
function init() {
if (document.getElementById("dA_DragnFav_header") == null) {
$("header[role='banner']").after("<div id='dA_DragnFav_header'>");
headerfilled=false;
}
makeDraggable();
if (document.getElementById("dA_DragnFav_styles") == null) {
$("head").append(
'<link id="dA_DragnFav_styles"' +
'href="//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/le-frog/jquery-ui.min.css" ' +
'rel="stylesheet" type="text/css">'
);
$("body").append("<ul id='dA_DragnFav_drowDown'></ul>");
$("#dA_DragnFav_drowDown").hide();
}
$(document).click(function(ev){$("#dA_DragnFav_drowDown").hide();})
}
if (window.top === window.self){
GM.getValue("hiddengroups","").then(ret=>{
if(ret!=""){
hiddengroups=JSON.parse(ret);
}
return GM.getValue("groupOrder","");
}).then(ret=>{
if(ret!=""){
groupOrder=JSON.parse(ret);
}
setInterval(init, 1000); // check every second
});
}
})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址