From 568ec6f9de3e7107fc6e26ae16a33ff987a8e223 Mon Sep 17 00:00:00 2001 From: 7dJx1qP <38586902+7dJx1qP@users.noreply.github.com> Date: Sat, 10 Sep 2022 14:33:35 -0400 Subject: [PATCH] initial commit --- .gitignore | 3 + CHANGELOG.md | 1 + README.md | 23 + build.py | 106 +++ config.py | 4 + .../public/StashDB Userscripts Bundle.user.js | 26 + dist/public/scene.css | 73 ++ images/allow-cors-tamper-monkey.png | Bin 0 -> 53987 bytes src/StashDBUserscriptLibrary.js | 634 ++++++++++++++++++ src/body/StashDB Copy StashID.user.js | 80 +++ src/header/StashDB Copy StashID.user.js | 21 + src/scene.css | 73 ++ 12 files changed, 1044 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 build.py create mode 100644 config.py create mode 100644 dist/public/StashDB Userscripts Bundle.user.js create mode 100644 dist/public/scene.css create mode 100644 images/allow-cors-tamper-monkey.png create mode 100644 src/StashDBUserscriptLibrary.js create mode 100644 src/body/StashDB Copy StashID.user.js create mode 100644 src/header/StashDB Copy StashID.user.js create mode 100644 src/scene.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a70558f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +dist/local +__pycache__ +stashdb-userscripts.code-workspace \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..825c32f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a037a9 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# StashDB Userscripts + +## [INSTALL USERSCRIPT](dist/public/StashDB%20Userscripts%20Bundle.user.js?raw=1) + +Installation requires a browser extension such as [Violentmonkey](https://violentmonkey.github.io/) / [Tampermonkey](https://www.tampermonkey.net/) / [Greasemonkey](https://www.greasespot.net/). + +> You may remove any unwanted userscripts from the bundle by removing the line that starts with `// @require` that corresponds to the userscript you wish to remove. + +![Allow cors - Tamper Monkey](images/allow-cors-tamper-monkey.png?raw=true "Allow cors - Tamper Monkey") + +## Developing + +Each userscript source is split into two files: +* `src/header` - Folder with userscript metadata blocks +* `src/body` - Folder with main script code + +Execute `py build.py` to combine source files and generate: +* a userscript bundle to `dist\local` for local development +* individual userscripts and a bundle to `dist\public` for release + +Build output directories: +* `dist\local` - A userscript bundle with `@require` headers that load the script code from local files (`src/body`) +* `dist\public` - Userscripts with `@require` headers that load the script code from this github repo \ No newline at end of file diff --git a/build.py b/build.py new file mode 100644 index 0000000..b81d3d1 --- /dev/null +++ b/build.py @@ -0,0 +1,106 @@ +import os +import config +import shutil +from pathlib import Path + +def get_active_branch_name(): + head_dir = Path(".") / ".git" / "HEAD" + with head_dir.open("r") as f: content = f.read().splitlines() + + for line in content: + if line[0:4] == "ref:": + return line.partition("refs/heads/")[2] + +def build(): + ROOTDIR = Path(__file__).parent.resolve() + LIBFILE = "StashDBUserscriptLibrary.js" + GIT_BRANCH = get_active_branch_name() + GITHUB_ROOT_URL = config.GITHUB_ROOT_URL.replace('%%BRANCH%%', GIT_BRANCH) + print('git branch', GIT_BRANCH) + + localbodyfiles = [] + distbodyfiles = [] + distlibfile = os.path.join(GITHUB_ROOT_URL, 'src', LIBFILE) + for file in os.listdir('src/header'): + # headerpath = os.path.join('src/header', file) + # bodypath = os.path.join('src/body', file) + # distpublicpath = os.path.join('dist/public', file) + # header = open(headerpath, 'r').read() + # body = open(bodypath, 'r').read() + + localbodyfiles.append("file://" + os.path.join(ROOTDIR, 'src/body', file)) + distbodyfiles.append(os.path.join(GITHUB_ROOT_URL, 'src/body', file)) + + # header = header.replace("%NAMESPACE%", config.NAMESPACE) \ + # .replace("%LIBRARYPATH%", distlibfile) \ + # .replace("%MATCHURL%", f"{config.SERVER_URL}/*") \ + # .replace("// @require %FILEPATH%\n", "") + # distscript = header + "\n\n" + body + # with open(distpublicpath, 'w') as f: + # f.write(distscript) + # print(distpublicpath) + + localpath = 'dist/local/StashDB Userscripts Development Bundle.user.js' + locallibfile = "file://" + os.path.join(ROOTDIR, 'src', LIBFILE) + with open(localpath, 'w') as f: + f.write(f"""// ==UserScript== +// @name StashDB Userscripts Development Bundle +// @namespace {config.NAMESPACE} +// @description StashDB Userscripts Development Bundle +// @version {config.BUNDLE_VERSION} +// @author 7dJx1qP +// @match {config.SERVER_URL}/* +// @resource IMPORTED_CSS file://{os.path.join(ROOTDIR, 'src')}\scene.css +// @grant unsafeWindow +// @grant GM_setClipboard +// @grant GM_getResourceText +// @grant GM_addStyle +// @grant GM.getValue +// @grant GM.setValue +// @grant GM.listValues +// @grant GM.xmlHttpRequest +// @connect localhost +// @require {locallibfile} +// +// ************************************************************************************************** +// * YOU MAY REMOVE ANY OF THE @require LINES BELOW FOR SCRIPTS YOU DO NOT WANT * +// ************************************************************************************************** +//\n""") + for localbodyfile in localbodyfiles: + f.write(f"// @require {localbodyfile}\n") + f.write("\n// ==/UserScript==\n") + print(localpath) + + distpath = 'dist/public/StashDB Userscripts Bundle.user.js' + with open(distpath, 'w') as f: + f.write(f"""// ==UserScript== +// @name StashDB Userscripts Bundle +// @namespace {config.NAMESPACE} +// @description StashDB Userscripts Bundle +// @version {config.BUNDLE_VERSION} +// @author 7dJx1qP +// @match {config.SERVER_URL}/* +// @resource IMPORTED_CSS https://raw.githubusercontent.com/7dJx1qP/stashdb-userscripts/{GIT_BRANCH}/dist/public/scene.css +// @grant unsafeWindow +// @grant GM_setClipboard +// @grant GM_getResourceText +// @grant GM_addStyle +// @grant GM.getValue +// @grant GM.setValue +// @grant GM.listValues +// @grant GM.xmlHttpRequest +// @connect localhost +// @require {distlibfile} +// +// ************************************************************************************************** +// * YOU MAY REMOVE ANY OF THE @require LINES BELOW FOR SCRIPTS YOU DO NOT WANT * +// ************************************************************************************************** +//\n""") + for distbodyfile in distbodyfiles: + f.write(f"// @require {distbodyfile}\n") + f.write("\n// ==/UserScript==\n") + print(distpath) + + shutil.copyfile('src/scene.css', 'dist/public/scene.css') + +build() \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..877e5a4 --- /dev/null +++ b/config.py @@ -0,0 +1,4 @@ +GITHUB_ROOT_URL = r"https://raw.githubusercontent.com/7dJx1qP/stashdb-userscripts/%%BRANCH%%/" +BUNDLE_VERSION = "0.1.1" +SERVER_URL = "https://stashdb.org" +NAMESPACE = "https://github.com/7dJx1qP/stashdb-userscripts" \ No newline at end of file diff --git a/dist/public/StashDB Userscripts Bundle.user.js b/dist/public/StashDB Userscripts Bundle.user.js new file mode 100644 index 0000000..a73eece --- /dev/null +++ b/dist/public/StashDB Userscripts Bundle.user.js @@ -0,0 +1,26 @@ +// ==UserScript== +// @name StashDB Userscripts Bundle +// @namespace https://github.com/7dJx1qP/stashdb-userscripts +// @description StashDB Userscripts Bundle +// @version 0.1.1 +// @author 7dJx1qP +// @match https://stashdb.org/* +// @resource IMPORTED_CSS https://raw.githubusercontent.com/7dJx1qP/stashdb-userscripts/master/dist/public/scene.css +// @grant unsafeWindow +// @grant GM_setClipboard +// @grant GM_getResourceText +// @grant GM_addStyle +// @grant GM.getValue +// @grant GM.setValue +// @grant GM.listValues +// @grant GM.xmlHttpRequest +// @connect localhost +// @require https://raw.githubusercontent.com/7dJx1qP/stashdb-userscripts/master/src\StashDBUserscriptLibrary.js +// +// ************************************************************************************************** +// * YOU MAY REMOVE ANY OF THE @require LINES BELOW FOR SCRIPTS YOU DO NOT WANT * +// ************************************************************************************************** +// +// @require https://raw.githubusercontent.com/7dJx1qP/stashdb-userscripts/master/src/body\StashDB Copy StashID.user.js + +// ==/UserScript== diff --git a/dist/public/scene.css b/dist/public/scene.css new file mode 100644 index 0000000..09f17b1 --- /dev/null +++ b/dist/public/scene.css @@ -0,0 +1,73 @@ +.stash_id_match a:hover { + background-color: rgba(0, 0, 0, 0.541); + color: #fff !important; +} + +.stash_id_match.search_match { + position: absolute; + top: 10px; + right: 10px; + align-self: center; +} + +.stash_id_match.scene_match { + position: relative; + margin-left: 10px; + cursor: pointer; + align-self: center; + display: inline; +} + +.match-yes { + color: green; +} + +.match-no { + color: red; +} + +.stash_id_ignored .match-no { + color: yellow; +} + +.stash_id_wanted .match-no { + color: gold; +} + +.stash_id_match svg { + height: 24px; + width: 24px; +} + +.stash-performer-link img { + width: 2rem; + padding-left: 0.5rem; +} + +.scene-performers .stash-performer-link { + padding-right: 0.25rem; +} + +.SearchPage .stash-performer-link img { + width: 2rem; + padding-left: 0rem; + margin-right: 10px; +} + +.stash_id_ignored, +.stash_id_ignored > .card { + background-color: rgba(48, 64, 77, 0.25) !important; +} + +.stash_id_ignored img { + opacity: 0.25; +} + +.settings-box { + padding: 1rem; + margin-bottom: 0; + position: absolute; + right: 0; + z-index: 999; + background-color: inherit; +} \ No newline at end of file diff --git a/images/allow-cors-tamper-monkey.png b/images/allow-cors-tamper-monkey.png new file mode 100644 index 0000000000000000000000000000000000000000..5e675bddf1bb697f9627e79324c0aa327772447f GIT binary patch literal 53987 zcmdqIWl&r}+bs%&1Si2Ag1fsWI1D<2dvJI65ZrZecXxMpcNyFX?g5gV$$P%9&OKGP z>YnrW?y9Njy{GrCp6;i2ueF}l;mV5AXvl=fFfcG^vN94N7#O%)7#P?ZL^$Y`X4v8y z=ohRrNLmc0dYbqYdIE1QsvrsjQx}W!X80a@j^rStY;z$_0dOV#q-+#ck){t@BHYMj9XLO2X;+L1nmhl=6RjlWh2EUAN9P8QdQdO)D9U>dgA zrP#c=u!0&+Q--*#A|mYf4OqM{5P=#a{h#sALCJhW7SKoca%~b`I`OTNl$3g0n>@2T zB3091S~9RFOd~!~%Z%tMsj8}Sd2V+WNgi(9^W@p&I1J5;jjDc&ZDL?xuxepD1(L(J z-t9_ZG7S|=(XiLjOTB|WwfJz^!N$MW9oC?3llU-L$35)wI#gJ4`4 z?=z-2(v`r&e>Vh1GFl<4BJdLD1gXg|82LB*Ing8{S=bmV8C$NB>&5{6pFg^I-8Jq~ zW4>omHNNko;Xb(-cU;N;7$hX>h>v*LKy!Xp;!5819iV#HEifZ~t@totd=gv!duecW zX}5b57cD$Ai2dq}pc?@C>Pem7eT*h{h7vu!A6Q02H&NO^x><2QCGZAxUQse|%^fji z7D;-a)9ux?G+#;;YdOhhorlf;JPOB)DLg}gM#ntjxvR2EB5?mrP#lo@%EcGe)Yr=V z;3R_KCF#9GOh&u()JZtRF0!5dTh(?APtg=J!1c$o(90$;$yT=LM)%aZX7|g%9G_yI zE=RbE-twW(UZY=NM=ZFU1)FtiUpG;W7Nl*#7nmd^lZC>k?Vv|ld(GYra9sC&t!&qN zqa~c!>ej`HD*E8L^8{y-eWHqARBTEE8O4cC(g>lu$F1rH}LP& ziDh}#9-bNUQQty0Kb<6+)C|G7?5jw#V9}(%OIvA%q1# z4F2?Gjhi_n9AF?XKKj)Se@3kWbmwf79{8|b1Ohbpvr*nRXsNf3ba2CKtI(p3(Dkh- z2{1Ez{n790w^);`A5Gx16P>r#Kf!_&AM&LuA21q@XgIbh$L4% zyqLZuqtW8Ic@w$2Ictl7BLx+K-P}Ix52eVrWqHzoMQz!{Pn0~dYEr@&n%&5;Desdo z&&y>t5V`Psz^GUKG*Jn2c>y_tNi`IYZy1u2x+LdTyS9MDCUHQIo=gDihgduBfPWp% zbB(^{6HW887wlk-Xf&~_cSgKtfe1RlRAAyHZj4(ma@E=dO=Rsd^2H};r$eg7ejN1Z z<{Rd_4e~uBi=ze2Xb+csgn@Brkl(D54Q?r5kueiuOBE$~V&Dop%Z$Gfo`ttlFnf-} z&@1<3g?9}mX?5p5Cy__{b^V=vJ8IbYO$K5vb(IvW>BVBY8AGjZn7t2Z^+ob>uMtZ$Pb&?Uu?xQejilvaT05W4vWn{m`js9G{ACT#f2x_ zh=+y{xTvu8sDUgcIgl0}t<|#rL3R5lS~IKr44b zaw07ev%vvKAxh!irq|4pA0UCrB)uP2NV7O!Xs1x!2DVEb-R$!$tLn2^_TccyjD)T^ zY$U~X*3v27cFKxHukTgsSmtH z%KG~3BHh#lNDUK`<`*Hk6d0#NAMQ|a@5K0NWlC38$}Bkw*hwG6nywd(Kd3}T5r#{K z(yZ4o7A&O;M7+rIdGUweqTS?mp*o9<4I3MBturq%95(u`d?x(54!+qj?0J%*OP~BK zTwD!YQ;>D3lBybHJ>eMg!694#m7%It&LjXBf!L_-{NtHlW8&93b%P70a+@k9Ey5z6 zLJ?|ifF35}YTc8XG$xhEWOuJ0U&M~D@gSI|Tq$M)C3{H_3+=q*nXmMtY70b(!ft=ouTE$KT%51jZcUbhkFEKideY)DZ`jjuxeB-nNT{W6F3vd3TPaYHF`F zdOKWauDpf$P%!I_z+xrX+7(a}9fb}I0uGVaOh53(T{;+j0BKSEQC9~-SM~+-ayx}v zc{aZ9?K}||(wq6QZC~k?KVqW>m)uF(ds${UhX!;LpX+WH>J^r1TcMx>)wqU=R6H`z z+}E-#xrJ@5^sJw{!!H-g7F++=CYM`AuG9xboVTQ9mu8ieT5V1hn$sU}a-6!r9p-j^ z5!9aq5eP!`1SiwCvEYgaqZquG})bl18p830dk2uZKyuJJqHFob}{nJbdezRoZl)cEMYOGkh{Xj`qA@XSH zETfiYW#hL!(yo!R$Vm_84`G2s$nj2GCSCd7ABOWfjDwH#al*8T;YpQ20btCBfNdJ1 z(k+6w8eaUrN|%5HNy`ay4J6Z4@`B^s#xfTtG4tUObU7j;zZy)LYQWQ*(VOR@F{K6!|O(IPTZKY8A-4u0F7V;LbN@fES)<>FWD z9&w+lm#TREs-bbYO&*%<-@_=;J$oVoCKOrN-!SD~RGyr$U60;cMM#nlc~L;`YVzaa zyCl5)Ys$&+>lJep+o~!X@ait8H$tb@rLSQ>yP}-u%kmV@_n?;LR-L(*FlncAEDN}^ z(b!Jw>(g9qfvw??C$cP3I8mJbEI!(#>Q)>PWnG$mz`?%^LTA~!sPDwiBi!&U$qziv z_w|l8iGVHno)u_)P$m|ZU3SlH=hJofC&(_4(;yt7-KQh!Y>neoTRc4*a4JQyb!^)= z!Ekq(ZDGSkh}5`(loOWrwU**JmH0=G^vVjK317XIS}EcJ)`NT#C(Wb}1)S0s7uGs) z;JPN&y}=rjR=l@bZxjOo$0JvHz3fmAJ&lD?feLi#g584G zItl-BE~zmt3HWh~%D*(q=>UO-s1C6w(K73OxKjhN3BY`6g1v24Pgql!jRNM4Bh_`8vjR@cD~cd_JlKM06ZkokK`vD zY5aSJj)5V$ZR^dx5Vifa7!!QtqfA?YUPGf<_y-y6u(DLifHty?vQOC;F>P$ zkV+_^1dm3_V=6Oj^7Cb1Lk6`ol}v2TrfwQ#N3gp2+R{?fjNx#HU@-GQAi^liD7D!! zY|d3&;$NeZU6^0>m|H?J^cfo+Zz9|Jw^{RRQU*dQwOF|EC)U!_@RCH??yqm%)#$f+ zdn4wf^Te~u4lN%jAq3!D#H^T}{ci_FO9!#AOl$`wZ&1W4R4|A^eJT%r;-#my0 zr~x8_WRR9-ja19`*^&4vPEuCu7potNcaUS=EMvVf$rfFBuR#=^eI3JuJ%E zrTJ-9hp%v*36$d~naQ$W&`F+E;2sBjO;reSj{|&ddG*ojsPf7T0<31FAuJ(QYn2a2 zZKZCK^t&ePY zZzN|=z+%YHKP)*xU(yN;E&3KIi7f8VK0`E|9x~63JMPx?*M6wcSujri zWh1vTTN9#%)4!Nji9W?821NLfSoZfJ`J;qK1;5FtYg@k8MG_qS%DA|=w4062QH??u z?LG3l9cd4+x+x~apUv-qzu&VPe8%h3OEDUdhbB0y97Hyb`oO0imntMz`SxV}snl(9 z&ERX_Vrs`M48LfVLYa%js6C!!LLwj@#ef})oO$(`oph*k@faIV$X=2Rs47n}PhIU^ zUaj}+wEU0$$=zRYgcZ{I=-QzHx+SnCYK3E@Zr;M?TXopLNR5Nuq`@*B+^ydd(69nj zU&KTW@~%!q!3@tQt}*>r?$G%pulWAu%XVH;kX*wt76diTsGFn3GcJ_KaE(fO3Pg8| zYwL25U_X@4&cm!>wFu}m{w4)>Vo^vwXuJQV`HY&8JXbE+RQ@X;L3-g_hlwbb)|{R@ za%p_+8H*gHO>8K(RcIxlj&t|fRI&T3UWc;eUC*Ov@6F7}J`=4$;Svi~!&-svEnLQ4 z*qe{pO2Q2az5e-No%#i!#z>|2DT*V2RHalkwp4%67)@KiMAl&;K9 z%`{?;!`Pio#5g$V`z>MEaLs5^X{}R?0`f1Xl>Kln>H@G2dzlM|A3vCtCbZ`Zrrfxy zoa-4sotR}&xNJkb3Wl3%S=mAyMQ+I+Vlt>4uR^V;_)(hwamv945l@f1gaIt?;4vju z`t$yfuRPvEyL#RtoJvc1Z98HlR1=W5EKX9H>dK}HVi7lVwjZf?+Q^}G%C!?<;Mx2Z=QRn zYgP}frch1mdwALp9hK$UPMtd+vV}ZGr*)Ve-2OURl45Y**@dDUi5FHFLNl*xb|I>F zfe0TbG-AGu%m0*zigP05CTbtmG-krRd3hFDpb;72OL%z3^2%^+`A^mAEAefn`GpmG zrz~Gwx2ipQH4WQqOEtyOl_x`$-EN@vnyP3}0+#^~1CxrI8MPmXG5;n6;~}Y#(p0jcyLZZZV1Nx)F1IKA8=9mr@9AI!|=Goo@u9=TK%2Hxo>M3 zu$PpYJ!g=OANgW03PgPbNr&=7nuX&tt(AA?>C01u_amYZ$qv8vU;i;kF7!7Ajxtkt zj+<)lN20icbRT&Y*6K0UxsHb80I>E6YoM zdy<&ywaa&o2yB#W>hf*6(u&rc03?_gb}#pLF6jkfVBEQPmSHe0T3S2GZIV-{NQii9 zdrB^3v&@1en_C?0%tEGH>zeOO_>Ng?X*-2yh@t_zkInI@2bERi1qTS(i1999^JRFD#Q36lP9ZUc%uzrDC8T79{JLBrG3j;PaqC)(F{M* z7@PaSYNP-yliN1JJG)rh(K7*{(2t1&Kv!P40Dg{zKp~nTc#wL=8fFv=6~4OG47RXeifj%6_H@Gvlkj zX>I6;i{@&hMP+xC$T;4Y<(}r9n}CpTqDykm`5g7{QX!KBEd8Q1t!=Q3?(t)saoluC zk+}|dl>9&!<|Dn>oc_afWmKqujRO_1>CNb-Iy%a;8@xxDIf2J%-};LU#DI4hlV|;H zX?YTA1#6uPWSGhLMtz$|8vs3O{}JcOAZe8VohIR6_2p&wceMNbf5p1!1(xfIeQlT^ zqCk?}x;i&B$s(n7myU|c-{Ez25=zefom+ArhFi_S{Bw|jnCQCA;=vc16&Tqc$m<`A znir1YPw1rp)sm1%gn|0_jLzE&4QFTqM6SFu%S)-$~?kts- z(iZhnzoA>GcN#wBu`T8&Ec zBR?*~M>z-WDB(99hADZ zar2&)U5malVB^+fLcy8#5C7@9rTnzW9L7ONvs5&ksq=mF)X^-48H7uQ9w$82Yz>Gp z$?aqnBCob>f*)pdNa4I^!$UQO3gFSO*SG(af5dmuQXK3=4rKmW0r|aD6C5uP7H+&ySxdvJv;mqhzzlSbnwYS);f5j1$hER%%|;8Cl? zsE8D-RQc-|<2f}DV`euPQq3fXI-BI3T#&(VFkd}k?aBLX{kyAU(O{fq~3A z9VdxPn&zeV?O8Whfim*a9>i>mqF}zuUnO5U8w{By@J7d3~v#ORg2{*8csBi><~6g^Oyb8HHInVh6S?6QlTvsm28tdqrP{6 z$wf``iJ$l5rg8)8MC144Wl(|RYfhE~W(zN{Gy-|fy?Qb1=822MO@81d6695urr-~B zzig;oz1TENA;E|$Mrw9K#6;$2r$)!8lx1|3Z&|3?T5{5R{B@jd$m0|xYA)^`5D^;a z8m0GL=be0%d{^J0rWlKK>du7M@4X+Q3eBqa!lxg*s3Es>L{nw}Tb;5*{ArYCR1HWv z87PsNo8Lt7H4-&LDv&gV^t$6QBsyAK71OIazz9ngeTHuAF#VhRXP$mXN_P8D;SOpr z8sXG*qQqpp1(y`#@P%;v4>^Nxx{Mi_D7wqTdt-!WghcDR*GzLO(|B+mixal#S#Be; z6i3|2o^zK;{PJ=@HxS39eSKx*x?raV<-LVK^Y-F3sM10{C7SI~sv`ESmegH@kaTv` z9K%+(Y2#x9pA*M{rs+3Ktd!Ag-W~c@egMu;edk_r5ryO0@n?;p zpMuE;QotgQP48g3d8WAy6GhtiAaBN#b)8OAP4yL%j19{xMC$lbU5-XmE$b)MO>XGI zfneB-3p1Xv_$_y!lH4xHDZKBDZ1Q?H#jDbFw2S@2_58ZS42>{h!)dUTdFh1MX?uu6 zl03xRR@Knnu6xVrGk_FTaP;ZB2c}7FtJ!-LPC0ysDU^=W#>)v(>gN6iL)(LpinL)^hgnF~4jkbWl z>e_}F^#*PIwZhAXd`e3UCHA2Kv6*-{@e%DB)-slA!=0rtFg_8bU;onjqCv40AIob7 zsgdmg$~6>exr@{y{wGKLH4VlN`YZG>g<}$fA|MzTWtv`_|Gv};?KtR>gapMW{|;pu zXzcwf{6Ft&<<5aqbVsJe!JhZje$M>a!pNW<_#VMgdT?fPfom;hFw!sei)Ue(k&Z+w zxkR(tHTiP^al~23Lv~mkpCV7n6*K(d#zD?B2H0Ilg&sKHld$6U3+Hb^oQfQIX_^el zA^X^W)lPqr`3mT~-RV|0EZ%@r}UPb7XjO*6lq)V`)1 zzR*;!6w_s$kEEX3O6#5p!o}3l3w)6}EcV~yVD2|hpIT`2`cUuZCvfB`B^dj(!~43w z612mldoIcBbktzva6{P~@}BB3v3d4AIhQmhSvt?OMsJ9A)Sl#gVZ@g`&hbMKyVCa2 zRJZ_I#9%hhDev!QuqN|-4f{$xKxg*bPnJth5wA-)N{o~`LXA~8+n?ExaLd&i9L}4_ zWS64jR^mY%b(=?(1hN)ijKr2K7f4T=Y-D*;?MNKxfyzvM>$}cfnRyVBTZ`aRDyDSm zO&5w;NL00@l~qjeJ};-y*a6_TS;wJ^#a=`4M5Lxe&Ae)Ctc;ki;t8U$^&3~F@Mo3> z6495!98bl+b!C4#R~or0g)yb4y<9rxTOhdow3fwzGfOW?F(+s~CSZC??k?Sv-j5zk zI=6wJR<33*a+yk$32pwtrg1Dh5%Q=YVxl4%q$B)y2h`+pi&_QlTopIcx-@$Gh$T*% zK+gqQoAymL^;>Ps&BANse8o_)x)Qni4z&*Ua<6H;u5@o-%tX}cl{>&hCKvTGlv1&{ z;E8BoYH40AtY6Q=RM&=ypRQ~u-fEAU%v+7niy9#QG^WzTJO#|equaK~sIDd*9CK*U zH~4FQq5$7kr`BHRqBpbHMwZ)jbEehd-AXZ+oyksCLSS2t7SO%>HyXM{pVR_PLufUP zL}-LRA!c%_3Z}388bO+vMU>o(mJq0AnX710v}#iGa7FNF96lPiAR%bRx!TB9TGZjsZ6$ zJp4R{MPo-qBqVB&;!&kX!^hb%=QcwP*f@8MGhvk){T>pT=5MrB$x95nh7GR6586up zNt${bYZa=~IQPMEdF|pd1mfWUyd5tR+m&_Vseaq!o7>1@ALTv!8~VaTJUUb0(oNw& zCsl-G@%h`Qk@KdpW`xWNZotjW^L%;s>f|_?gSE(E?PMK%nw&CERhcWP>8(O?{yE_y zD!ZCh?CtjvHfh8h(tB&+D=GxI_)i741FXQdwB-3LB~ z|B{<^<<|G(#?O8A)9bW(%o(c)4uu>l*0q1^1>SE&`-)nx$)q@J4|BH`HpSAm-+_tS zjs8rN5C4P)gI!d*WikZRJ-%wrcfWzcK-l-N-bfN&Y?moJb1RxSJd7A9J?jWEyP~d1 zpu3^nZyzW_mBaipEWLvP79go-exe^6+j@TQUWaDCv1gPO9dhEN8&Ri%yJnYFKo;Kn zk~7Ci__VXCS-dUgda$)#6yerquRU$yzTdj*nq(|#4nG8*j6C*FbMQ}#~3~?eS>%es4dP&dRDV?SxD*Wp2PBhA-cYg z5;i&{(?n5*v~CSgpwd;XUzlKwi@^vTzuoJ7;w189mfPBvjeF&|uQoEzwNo!7{}_#B zOsdQpwqi%Kb(DrDt-4@_x%0(&EKyikj@WDdWuDf?t7kr3|7qrz{7Qct93H#kITC47 zeMN)(G04gy9D+ri^O@P zPz0Qxg6#4`_CeD^`f;qZfhMKK<4xcpI^`*d6--@b;~{Cds#FN z-$0FFjvDQp)J{tz}QwP;SV*SK%TrNy_0INMuc0zctZG^$R=Mq1~M)9g=0Po-;@unxZ! zg`XSv5V^9<@fi>C@MohgC?2mf0e(1Y3;N7SFo46{nr2o1P-gNSVK{#+eaY8GZ;>-o z6|*TrD7uK?@>lSt3z+1>aVDYzv9R+Mb8jqtnnEFvJrYTlEdsTT(q+2stjF_^V$hkn zg_6;@XPh|OIXxRmn7&4F6^#t5_u~W91$fw^&G5!C7-`9*#s0`|({w-W$Ob?0dn?DJ z_4U$JB=$ur50Kxhi??u!g?{^r-UUNok>TtNrrm-=#0uH(j?0| z>7?+7i8~UIxr3L-FbYR7vU`{S`WV9sOb||46iM)wt0;V4bIpc4yjh`v>2$FqSYrgH z@*zQqx@|HfLNh(T4xPxuXHv4|=;$7Zvwp3$YHiLoFA)*%B)JNxzMf(vYlE`9HUE)S zRhl)6dR}Y46KWUcMB>ArlI<3g>pqa>Evn!oN-!SzFmd^m-93F?@`O#TRMDi?Q54`0 zYck-zT!(%+5B_vk$~U)~)%6{k>VVs{jYs&l&H%gMWO$XjA+r<5>TfrLt_h0lxk>*3 zU}qp7i2!7+wwRulRL|VC`56Mq%Y)orTM3xQ!<01v6;1#9A}q#(B~ITTZtAgGS( zGE+)^mUuP4ky4edqb8f=n6Ade>tCb^_2rK~Q`R?bwuyLtG0wM_c9S~#88xBznB@@> z3C)DspB0{2g4E^#iBo&|-ca5jfgGI$01bW~CYtF8Hl>HHYPhuEUH$~Fy75pCRc>G~ zMWyDyY9gC&TSk=2)S^0MO&5%}Ue0T;sL`Ulx@1RQ6J zxfXu>S>NbMwgtnLYaCPCFS7H0?RKEYtVGCnv9S5D%ofK>KJk_%HwQ=bY>t0;ga(Ae zB(TH|T&u|zY+iPN;moZcL~+$~@H>j_S0LFJ-BVvYOz5=Eedu^u^$XPpn>Aa2mAs6w zRR6U1TT;&HkKXL8sAHG}7P{!``hV`}IyE-oqSXCt7x$NjV0%L05v_lVa9>^e&>8le zB-3q8aqXPBt&d5Gre~KvP?&Sjw8yq$z781pp+u;Sl`ZCdRNKQgY|WiXhok4#0NuA{ zF#dP2g}8@OBv1N<%kZw_GuG-^Ombv>N)Q(DKR8QG zS^^s^MO_25PTwyD_}s$!NH=6MPh(5WE4UaZ75!HWZatK6+`^92K7%)B`hwGp&3?~U zPSg0}dLkSLhD4if+T6-i)28Z-emZY17 zCWP#T6KEF|uT6k1V_FwWAt}a_YgF9QRR*T6p>WM|wt29Ne;LXaJZV!qJ{fKSCM@z@bfUj zOmxfAn@^Mhx!QM_Zzx((Q&2COMie)!ex<#O&dNXc(0R7x7jF4RH1@3}CRZ zPQ#nM)>tjbP+rT&og($;+gq;XS~eu-cHICMe2HUm^}Bl574MLoLicBftMUDa z=i`NxP&7w7e⋙1=|0MFKb$RoI0mzufX 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�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 literal 0 HcmV?d00001 diff --git a/src/StashDBUserscriptLibrary.js b/src/StashDBUserscriptLibrary.js new file mode 100644 index 0000000..058d436 --- /dev/null +++ b/src/StashDBUserscriptLibrary.js @@ -0,0 +1,634 @@ +// StashDB Userscript Library +// Exports utility functions and a StashDB class that emits events whenenever a page navigation change is detected +// version 0.1.0 + +(function () { + 'use strict'; + + const css = GM_getResourceText("IMPORTED_CSS"); + GM_addStyle(css); + + const STASH_IMAGE = 'data:image/png;base64,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'; + + const stashdb = function () { + + const { fetch: originalFetch } = window; + const stashdbListener = new EventTarget(); + + unsafeWindow.fetch = async (...args) => { + let [resource, config ] = args; + // request interceptor here + const response = await originalFetch(resource, config); + // response interceptor here + const contentType = response.headers.get("content-type"); + if (contentType && contentType.indexOf("application/json") !== -1) { + const data = await response.clone().json(); + stashdbListener.dispatchEvent(new CustomEvent('response', { 'detail': data })); + } + return response; + }; + + class Logger { + constructor(enabled) { + this.enabled = enabled; + } + debug() { + if (!this.enabled) return; + console.debug(...arguments); + } + } + + function waitForElementId(elementId, callBack, time) { + time = (typeof time !== 'undefined') ? time : 100; + window.setTimeout(() => { + const element = document.getElementById(elementId); + if (element) { + callBack(elementId, element); + } else { + waitForElementId(elementId, callBack); + } + }, time); + } + + function waitForElementClass(elementId, callBack, time) { + time = (typeof time !== 'undefined') ? time : 100; + window.setTimeout(() => { + const element = document.getElementsByClassName(elementId); + if (element.length > 0) { + callBack(elementId, element); + } else { + waitForElementClass(elementId, callBack); + } + }, time); + } + + function waitForElementByXpath(xpath, callBack, time) { + time = (typeof time !== 'undefined') ? time : 100; + window.setTimeout(() => { + const element = getElementByXpath(xpath); + if (element) { + callBack(xpath, element); + } else { + waitForElementByXpath(xpath, callBack); + } + }, time); + } + + function getElementByXpath(xpath, contextNode) { + return document.evaluate(xpath, contextNode || document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + } + + function getElementsByXpath(xpath, contextNode) { + return document.evaluate(xpath, contextNode || document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); + } + + function getClosestAncestor(el, selector, stopSelector) { + let retval = null; + while (el) { + if (el.matches(selector)) { + retval = el; + break + } else if (stopSelector && el.matches(stopSelector)) { + break + } + el = el.parentElement; + } + return retval; + } + + function insertAfter(newNode, existingNode) { + existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling); + } + + function createElementFromHTML(htmlString) { + const div = document.createElement('div'); + div.innerHTML = htmlString.trim(); + + // Change this to div.childNodes to support multiple top-level nodes. + return div.firstChild; + } + + + function setNativeValue(element, value) { + const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set; + const prototype = Object.getPrototypeOf(element); + const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set; + + if (valueSetter && valueSetter !== prototypeValueSetter) { + prototypeValueSetter.call(element, value); + } else { + valueSetter.call(element, value); + } + } + + function updateTextInput(element, value) { + setNativeValue(element, value); + element.dispatchEvent(new Event('input', { bubbles: true })); + } + + function concatRegexp(reg, exp) { + let flags = reg.flags + exp.flags; + flags = Array.from(new Set(flags.split(''))).join(); + return new RegExp(reg.source + exp.source, flags); + } + + function sortElementChildren(node) { + const items = node.childNodes; + const itemsArr = []; + for (const i in items) { + if (items[i].nodeType == Node.ELEMENT_NODE) { // get rid of the whitespace text nodes + itemsArr.push(items[i]); + } + } + + itemsArr.sort((a, b) => { + return a.innerHTML == b.innerHTML + ? 0 + : (a.innerHTML > b.innerHTML ? 1 : -1); + }); + + for (let i = 0; i < itemsArr.length; i++) { + node.appendChild(itemsArr[i]); + } + } + + function xPathResultToArray(result) { + let node = null; + const nodes = []; + while (node = result.iterateNext()) { + nodes.push(node); + } + return nodes; + } + + const reloadImg = url => + fetch(url, { cache: 'reload', mode: 'no-cors' }) + .then(() => document.body.querySelectorAll(`img[src='${url}']`) + .forEach(img => img.src = url)); + + function isInViewport(element) { + const rect = element.getBoundingClientRect(); + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); + } + + const checkLabel = ''; + const timesLabel = ''; + const clearLabel = ''; + const starLabel = ''; + + class StashDB extends EventTarget { + constructor({ pageUrlCheckInterval = 50, logging = false } = {}) { + super(); + this.stashUrl = 'http://localhost:9999'; + this.loggedIn = false; + this.userName = null; + this.log = new Logger(logging); + this._pageUrlCheckInterval = pageUrlCheckInterval; + this.fireOnHashChangesToo = true; + this.pageURLCheckTimer = setInterval(() => { + // Loop every 500ms + if (this.lastPathStr !== location.pathname || this.lastQueryStr !== location.search || (this.fireOnHashChangesToo && this.lastHashStr !== location.hash)) { + this.lastPathStr = location.pathname; + this.lastQueryStr = location.search; + this.lastHashStr = location.hash; + this.gmMain(); + } + }, this._pageUrlCheckInterval); + stashdbListener.addEventListener('response', (evt) => { + //this.processScenes(evt.detail); + //this.processPerformers(evt.detail); + this.dispatchEvent(new CustomEvent('stashdb:response', { 'detail': evt.detail })); + }); + } + async callGQL(reqData) { + const options = { + method: 'POST', + body: JSON.stringify(reqData), + headers: { + 'Content-Type': 'application/json' + } + } + if (this.stashApiKey) { + options.headers.ApiKey = this.stashApiKey; + } + + return new Promise((resolve, reject) => { + GM.xmlHttpRequest({ + method: "POST", + url: this.stashUrl + '/graphql', + data: JSON.stringify(reqData), + headers: { + "Content-Type": "application/json" + }, + onload: response => { + resolve(JSON.parse(response.response)); + }, + onerror: reject + }); + }); + } + async findSceneByStashId(id) { + const reqData = { + "variables": { id }, + "query": `query FindSceneByStashId($id: String!) { + findScenes(scene_filter: {stash_id: {value: $id, modifier: EQUALS}}) { + scenes { + title + stash_ids { + endpoint + stash_id + } + id + } + } + }` + } + return this.callGQL(reqData); + } + /*async processScenes(data) { + if (data?.data?.queryScenes?.scenes) { + return Promise.all(data?.data?.queryScenes?.scenes.map(scene => this.processListScene(scene.id))); + } + }*/ + async processListScene(stashId, sceneEl) { + const data = await this.findSceneByStashId(stashId); + const localId = data?.data?.findScenes?.scenes[0]?.id; + waitForElementByXpath(`//div[@class='card-footer']//a[contains(@href,'${stashId}')]`, async (xpath, el) => { + await this.addSceneMarker(stashId, localId, el.parentElement, sceneEl); + }); + } + async processPageScene(stashId) { + const data = await this.findSceneByStashId(stashId); + const localId = data?.data?.findScenes?.scenes[0]?.id; + waitForElementByXpath(`//div[contains(@class,'scene-info')]/div[@class='card-header']/div[@class='float-end']`, async (xpath, el) => { + await this.addSceneMarker(stashId, localId, el, getClosestAncestor(el, '.scene-info')); + }); + } + async processSearchScene(stashId, sceneEl) { + const data = await this.findSceneByStashId(stashId); + const localId = data?.data?.findScenes?.scenes[0]?.id; + waitForElementByXpath(`//a[contains(@href,'${stashId}')]//h5`, async (xpath, el) => { + el.classList.add('d-flex'); + const markerEl = await this.addSceneMarker(stashId, localId, el, sceneEl); + markerEl.classList.add('ms-auto'); + }); + } + async addSceneMarker(stashId, localId, parentElement, sceneEl) { + let markerEl = parentElement.querySelector('.stash_id_match'); + if (!markerEl) { + let label = localId ? checkLabel : timesLabel; + + const sceneState = JSON.parse(await GM.getValue(stashId, '{"ignored":false,"wanted":false}')); + if (sceneState.ignored) { + sceneEl.classList.add('stash_id_ignored'); + label = clearLabel; + } + else if (sceneState.wanted) { + sceneEl.classList.add('stash_id_wanted'); + label = starLabel; + } + + markerEl = createElementFromHTML(``); + markerEl.classList.add(localId ? 'match-yes' : 'match-no'); + + let dropdownEl; + markerEl.addEventListener('mouseenter', evt => { + dropdownEl = createElementFromHTML(``); + markerEl.appendChild(dropdownEl); + + const rect = document.body.getBoundingClientRect(); + const rect2 = evt.currentTarget.getBoundingClientRect(); + const x = rect2.left;// - rect.left; + const y = rect2.top;// - rect.top; + dropdownEl.style.left = `${x}px`; + dropdownEl.style.top = `${y}px`; + + dropdownEl.addEventListener("click", evt => { + evt.preventDefault(); + evt.stopImmediatePropagation(); + }); + + const menuEl = createElementFromHTML(``); + dropdownEl.appendChild(menuEl); + + if (localId) { + const localLink = this.stashUrl + '/scenes/' + localId; + const gotoSceneEl = createElementFromHTML(`Go to Scene`); + gotoSceneEl.addEventListener("click", evt => { + evt.preventDefault(); + evt.stopImmediatePropagation(); + window.open( + localLink, + '_blank' + ); + }); + menuEl.appendChild(gotoSceneEl); + } + else { + const ignoreEl = createElementFromHTML(``); + const wishlistEl = createElementFromHTML(`>`); + + if (sceneState.ignored) { + ignoreEl.innerText = 'Clear Ignore'; + + ignoreEl.addEventListener("click", async evt => { + evt.preventDefault(); + evt.stopImmediatePropagation(); + sceneState.ignored = false; + sceneEl.classList.remove('stash_id_ignored'); + markerEl.querySelector('a').innerHTML = timesLabel; + GM.setValue(stashId, JSON.stringify(sceneState)); + menuEl.remove(); + }); + + menuEl.append(ignoreEl); + } + else if (sceneState.wanted) { + wishlistEl.innerText = 'Remove From Wishlist'; + + wishlistEl.addEventListener("click", async evt => { + evt.preventDefault(); + evt.stopImmediatePropagation(); + sceneState.wanted = false; + sceneEl.classList.remove('stash_id_wanted'); + markerEl.querySelector('a').innerHTML = timesLabel; + GM.setValue(stashId, JSON.stringify(sceneState)); + menuEl.remove(); + }); + + menuEl.append(wishlistEl); + } + else { + wishlistEl.innerText = 'Add to Wishlist'; + ignoreEl.innerText = 'Ignore Scene'; + + wishlistEl.addEventListener("click", async evt => { + evt.preventDefault(); + evt.stopImmediatePropagation(); + sceneState.wanted = true; + sceneEl.classList.add('stash_id_wanted'); + markerEl.querySelector('a').innerHTML = starLabel; + GM.setValue(stashId, JSON.stringify(sceneState)); + menuEl.remove(); + }); + + ignoreEl.addEventListener("click", async evt => { + evt.preventDefault(); + evt.stopImmediatePropagation(); + sceneState.ignored = true; + sceneEl.classList.add('stash_id_ignored'); + markerEl.querySelector('a').innerHTML = clearLabel; + GM.setValue(stashId, JSON.stringify(sceneState)); + menuEl.remove(); + }); + + menuEl.append(wishlistEl); + menuEl.append(ignoreEl); + } + } + + if(!isInViewport(menuEl)) { + dropdownEl.style.left = `${x-150}px`; + dropdownEl.style.top = `${y-80}px`; + } + + }); + markerEl.addEventListener('mouseleave', () => { + dropdownEl.remove(); + }); + parentElement.appendChild(markerEl); + } + return markerEl; + } + async createStashPerformerLink(stashId, callback) { + const reqData = { + "variables": { + "performer_filter": { + "stash_id": { + "value": stashId, + "modifier": "EQUALS" + } + } + }, + "query": `query FindPerformers($filter: FindFilterType, $performer_filter: PerformerFilterType) { + findPerformers(filter: $filter, performer_filter: $performer_filter) { + count + performers { + id + } + } + }` + } + const results = await this.callGQL(reqData); + if (results.data.findPerformers.count === 0) return; + const performerId = results.data.findPerformers.performers[0].id; + const performerUrl = `${this.stashUrl}/performers/${performerId}`; + const performerLink = document.createElement('a'); + performerLink.classList.add('stash-performer-link'); + performerLink.href = performerUrl; + const stashIcon = document.createElement('img'); + stashIcon.src = STASH_IMAGE; + performerLink.appendChild(stashIcon); + performerLink.setAttribute('target', '_blank'); + callback(performerLink); + } + addStashPerformerLinks() { + if (!document.querySelector('.stash-performer-link')) { + for (const searchPerformer of document.querySelectorAll('div.PerformerCard a')) { + const url = new URL(searchPerformer.href); + const stashId = url.pathname.replace('/performers/', ''); + const searchPerformerHeader = searchPerformer.querySelector('div.card-footer > h5'); + this.createStashPerformerLink(stashId, function (performerLink) { + searchPerformerHeader.appendChild(performerLink); + performerLink.addEventListener('click', function (event) { + event.preventDefault(); + window.open(performerLink.href, '_blank'); + }); + }); + } + } + } + addStashPerformerLink() { + if (!document.querySelector('.stash-performer-link')) { + const header = document.querySelector('.card-header h3'); + const stashId = window.location.pathname.replace('/performers/', ''); + this.createStashPerformerLink(stashId, function (performerLink) { + header.appendChild(performerLink); + }); + } + } + addStashScenePerformerLink() { + if (!document.querySelector('.stash-performer-link')) { + const header = document.querySelector('.scene-performers'); + for (const scenePerformer of document.querySelectorAll('a.scene-performer')) { + const url = new URL(scenePerformer.href); + const stashId = url.pathname.replace('/performers/', ''); + this.createStashPerformerLink(stashId, function (performerLink) { + header.insertBefore(performerLink, scenePerformer); + }); + } + } + } + addStashSearchPerformerLink() { + if (!document.querySelector('.stash-performer-link')) { + for (const searchPerformer of document.querySelectorAll('a.SearchPage-performer')) { + const url = new URL(searchPerformer.href); + const stashId = url.pathname.replace('/performers/', ''); + const searchPerformerHeader = searchPerformer.querySelector('div.card > div.ms-3 > h4 > span'); + this.createStashPerformerLink(stashId, function (performerLink) { + searchPerformerHeader.parentElement.insertBefore(performerLink, searchPerformerHeader); + performerLink.addEventListener('click', function (event) { + event.preventDefault(); + window.open(performerLink.href, '_blank'); + }); + }); + } + } + } + matchUrl(location, fragment) { + const regexp = concatRegexp(new RegExp(location.origin), fragment); + this.log.debug(regexp, location.href.match(regexp)); + return location.href.match(regexp) != null; + } + gmMain() { + const location = window.location; + this.log.debug(URL, window.location); + + waitForElementByXpath('//button[contains(@class, "login-button")]|//span[text()="Logged in as"]/following-sibling::a', async (xpath, el) => { + this.loggedIn = el.tagName === 'A'; + this.userName = this.loggedIn ? el.innerText : null; + + if (this.loggedIn && !document.querySelector('.settings-box')) { + const gearIcon = ``; + const settingsEl = createElementFromHTML(`${gearIcon}`); + el.parentElement.appendChild(settingsEl); + const settingsMenuEl = createElementFromHTML(``); + settingsEl.appendChild(settingsMenuEl); + + settingsEl.addEventListener('click', evt => { + if (settingsMenuEl.style.display === 'none') { + settingsMenuEl.style.display = 'block'; + } + else { + settingsMenuEl.style.display = 'none'; + } + }); + + settingsMenuEl.addEventListener('click', evt => { + evt.stopPropagation(); + }); + + this.stashUrl = await GM.getValue('stashAddress', 'http://localhost:9999'); + const stashAddress = document.getElementById('address'); + stashAddress.value = this.stashUrl; + stashAddress.addEventListener('change', async () => { + await GM.setValue('stashAddress', stashAddress.value || 'http://localhost:9999'); + }); + + this.stashApiKey = await GM.getValue('stashApiKey', ''); + const stashApiKey = document.getElementById('apiKey'); + stashApiKey.value = this.stashApiKey; + stashApiKey.addEventListener('change', async () => { + await GM.setValue('stashApiKey', stashApiKey.value || ''); + }); + } + + const [_, stashType, stashId, action] = location.pathname.split('/'); + if (location.pathname === '/' || + (stashType === 'scenes' && !stashId) || + (stashType === 'performers' && stashId && !action) || + (stashType === 'studios' && stashId && !action) || + (stashType === 'tags' && stashId && !action)) { + waitForElementByXpath('(//div[contains(@class, "HomePage-scenes")]/div[@class="col"]|//div[@class="scenes-list"]/div[@class="row"]/div[@class="col-3"])/div[contains(@class, "SceneCard")]', (xpath, el) => { + const sceneCards = document.querySelectorAll('.row .SceneCard'); + for (const sceneCard of sceneCards) { + const stashId = getElementByXpath("./div[@class='card-footer']//a/@href", sceneCard).value.replace('/scenes/', ''); + this.processListScene(stashId, sceneCard); + } + }); + } + else if (stashType === 'scenes' && stashId && !action) { + this.processPageScene(stashId); + } + else if (stashType === 'search' && stashId && !action) { + waitForElementByXpath('//div[@class="SearchPage"]/div[@class="row"]/div[@class="col-6"]/h3[text()="Scenes"]', (xpath, el) => { + const sceneCards = document.querySelectorAll('.SearchPage-scene'); + for (const sceneCard of sceneCards) { + const stashId = sceneCard.href.split('/').pop(); + this.processSearchScene(stashId, sceneCard); + } + }); + } + + if (stashType === 'performers' && !stashId) { + waitForElementClass('PerformerCard', (className, el) => { + this.addStashPerformerLinks(); + }); + } + if (stashType === 'performers' && stashId && !action) { + waitForElementClass('PerformerInfo', (className, el) => { + this.addStashPerformerLink(); + }); + } + else if (stashType === 'scenes' && stashId && !action) { + waitForElementClass('scene-performers', (className, el) => { + this.addStashScenePerformerLink(); + }); + } + else if (stashType === 'search' && stashId && !action) { + waitForElementClass('SearchPage-performer', (className, el) => { + this.addStashSearchPerformerLink(); + }); + } + + if (location.pathname === '/') { + this.log.debug('[Navigation] Home Page'); + } + this.dispatchEvent(new CustomEvent('page', { 'detail': { stashType, stashId, action } })); + }); + } + } + + return { + stashdb: new StashDB({ logging: false }), + StashDB, + waitForElementId, + waitForElementClass, + waitForElementByXpath, + getElementByXpath, + getElementsByXpath, + getClosestAncestor, + insertAfter, + createElementFromHTML, + setNativeValue, + updateTextInput, + sortElementChildren, + xPathResultToArray, + reloadImg, + Logger, + }; + }; + + if (!unsafeWindow.stashdb) { + unsafeWindow.stashdb = stashdb(); + } +})(); \ No newline at end of file diff --git a/src/body/StashDB Copy StashID.user.js b/src/body/StashDB Copy StashID.user.js new file mode 100644 index 0000000..1d204cd --- /dev/null +++ b/src/body/StashDB Copy StashID.user.js @@ -0,0 +1,80 @@ +(function() { + 'use strict'; + + const { + stashdb, + StashDB, + waitForElementId, + waitForElementClass, + waitForElementByXpath, + getElementByXpath, + sortElementChildren, + createElementFromHTML, + } = unsafeWindow.stashdb; + + function createTooltipElement() { + const copyTooltip = document.createElement('span'); + copyTooltip.setAttribute('id', 'copy-tooltip'); + copyTooltip.innerText = 'Copied!'; + copyTooltip.classList.add('fade', 'hide'); + copyTooltip.style.position = "absolute"; + copyTooltip.style.left = '0px'; + copyTooltip.style.top = '0px'; + copyTooltip.style.marginLeft = '40px'; + copyTooltip.style.padding = '5px 12px'; + copyTooltip.style.backgroundColor = '#000000df'; + copyTooltip.style.borderRadius = '4px'; + copyTooltip.style.color = '#fff'; + document.body.appendChild(copyTooltip); + return copyTooltip; + } + + function createCopyButton() { + const copyBtn = document.createElement('button'); + copyBtn.setAttribute('id', 'copy-stashid'); + copyBtn.title = 'Copy to clipboard'; + copyBtn.innerHTML = `Copy StashID`; + copyBtn.classList.add('btn', 'btn-secondary', 'btn-sm', 'minimal', 'ml-1'); + copyBtn.addEventListener('click', evt => { + GM_setClipboard(window.location.pathname.split('/').pop()); + const copyTooltip = createTooltipElement(); + const rect = document.body.getBoundingClientRect(); + const rect2 = evt.currentTarget.getBoundingClientRect(); + const x = rect2.left - rect.left; + const y = rect2.top - rect.top; + copyTooltip.classList.add('show'); + copyTooltip.style.left = `${x}px`; + copyTooltip.style.top = `${y}px`; + setTimeout(() => { + copyTooltip.remove(); + }, 500); + }); + return copyBtn; + } + + stashdb.addEventListener('page', evt => { + const { stashType, stashId, action } = evt.detail; + + waitForElementByXpath("//div[contains(@class, 'navbar-nav')]", (xpath, el) => { + if ((stashType === 'scenes' && stashId && !action) || + (stashType === 'performers' && stashId && !action) || + (stashType === 'studios' && stashId && !action)) { + if (!document.getElementById('copy-stashid')) { + el.appendChild(createCopyButton()); + } + else { + document.getElementById('copy-stashid').style.display = 'inline-block'; + } + } + else if (document.getElementById('copy-stashid')) { + document.getElementById('copy-stashid').style.display = 'none'; + } + }); + + + }); + + + + +})(); \ No newline at end of file diff --git a/src/header/StashDB Copy StashID.user.js b/src/header/StashDB Copy StashID.user.js new file mode 100644 index 0000000..44a8165 --- /dev/null +++ b/src/header/StashDB Copy StashID.user.js @@ -0,0 +1,21 @@ +// ==UserScript== +// @name StashDB Copy StashID +// @namespace https://github.com/7dJx1qP/stashdb-userscripts +// @description StashDB Copy StashID +// @version 0.1.0 +// @author 7dJx1qP +// @match https://stashdb.org/* +// @resource IMPORTED_CSS https://raw.githubusercontent.com/7dJx1qP/stashdb-userscripts/dist/public/scene.css +// @grant unsafeWindow +// @grant GM_setClipboard +// @grant GM_getResourceText +// @grant GM_addStyle +// @grant GM.getValue +// @grant GM.setValue +// @grant GM.listValues +// @grant GM.xmlHttpRequest +// @require %LIBRARYPATH% +// @require %FILEPATH% +// @run-at document-start + +// ==/UserScript== \ No newline at end of file diff --git a/src/scene.css b/src/scene.css new file mode 100644 index 0000000..09f17b1 --- /dev/null +++ b/src/scene.css @@ -0,0 +1,73 @@ +.stash_id_match a:hover { + background-color: rgba(0, 0, 0, 0.541); + color: #fff !important; +} + +.stash_id_match.search_match { + position: absolute; + top: 10px; + right: 10px; + align-self: center; +} + +.stash_id_match.scene_match { + position: relative; + margin-left: 10px; + cursor: pointer; + align-self: center; + display: inline; +} + +.match-yes { + color: green; +} + +.match-no { + color: red; +} + +.stash_id_ignored .match-no { + color: yellow; +} + +.stash_id_wanted .match-no { + color: gold; +} + +.stash_id_match svg { + height: 24px; + width: 24px; +} + +.stash-performer-link img { + width: 2rem; + padding-left: 0.5rem; +} + +.scene-performers .stash-performer-link { + padding-right: 0.25rem; +} + +.SearchPage .stash-performer-link img { + width: 2rem; + padding-left: 0rem; + margin-right: 10px; +} + +.stash_id_ignored, +.stash_id_ignored > .card { + background-color: rgba(48, 64, 77, 0.25) !important; +} + +.stash_id_ignored img { + opacity: 0.25; +} + +.settings-box { + padding: 1rem; + margin-bottom: 0; + position: absolute; + right: 0; + z-index: 999; + background-color: inherit; +} \ No newline at end of file