Advertisement
Guest User

BIC EDIT

a guest
Mar 27th, 2024
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.58 KB | None | 0 0
  1. // ==UserScript==
  2. // @name BIC EDIT - https://rentry.org/bicedit
  3. // @description Allows to regenerate an image as square, landscape or portrait with the possibility of fine-tuning it with an additional prompt
  4. // @version 1.2
  5. // @match https://copilot.microsoft.com/images/create*
  6. // @match https://www.bing.com/images/create*
  7. // @grant GM.setValue
  8. // @grant GM.getValue
  9. // @grant unsafeWindow
  10. // @grant GM.xmlHttpRequest
  11. // ==/UserScript==
  12.  
  13. // Default suggestions for the style textbox, edit these to match your preferences
  14. // "item1",
  15. // "item2",
  16. // Set enableSuggestions to false to disable them
  17.  
  18. var enableSuggestions = true;
  19. var styleSuggestions = [
  20. "(Open this userscript source code to edit these presets)",
  21. "monochrome dot-printed manga-style",
  22. "watercolor",
  23. "mmd 3d render",
  24. "fluorescent fiery colors"
  25. ];
  26.  
  27. var refreshIterationsNeeded = 7;
  28. var isiframe = true;
  29. var styleTb = null;
  30. var aspectRatioCb = null;
  31. var lastRegen = 0;
  32. var t = null;
  33.  
  34. // prevent the script from running on already edited generations since it won't work
  35. if (shouldExecute()) {
  36. t = setInterval(update, 1000);
  37. window.addEventListener('popstate', function (event) {
  38. if (t == null) {
  39. console.log("started interval");
  40. t = setInterval(update, 1000);
  41. }
  42. });
  43. } else {
  44. checkEditedGenerationImagePage();
  45. }
  46.  
  47. function shouldExecute() {
  48. var urlParams = new URLSearchParams(window.location.search);
  49. return urlParams.get("_dbe") === null && window.top === window.self;
  50. }
  51.  
  52. function checkEditedGenerationImagePage() {
  53. var errorMsg = document.getElementsByClassName("gil_err_mt");
  54. var errorDesc = document.getElementsByClassName("gil_err_sbt");
  55. var errorImg = document.getElementsByClassName("gil_err_img rms_img");
  56. var notFound = errorMsg.length > 0 && errorMsg[0].innerText == "Page not found.";
  57. if (!notFound) {
  58. addQueryParamToResult();
  59. return;
  60. }
  61. var useOldBehavior = false;
  62. var refreshInterval = null;
  63. errorImg[0].src = "https://r.bing.com/rp/TX9QuO3WzcCJz1uaaSwQAz39Kb0.jpg";
  64. var updateText = function () {
  65. errorMsg[0].innerText = "Image generation in progress";
  66. errorDesc[0].innerText = useOldBehavior ? "This page will refresh automatically every 7 seconds. If the image doesn't appears within 40 seconds, it was most likely filtered and you can close this tab. Refreshing in " + refreshIterationsNeeded + "s..." : "Periodically checking this image generation status...";
  67. }
  68. updateText();
  69. var oldBehavior = function () {
  70. if (--refreshIterationsNeeded <= 0) {
  71. location.reload();
  72. clearInterval(refreshInterval);
  73. } else {
  74. updateText();
  75. }
  76. };
  77.  
  78. var urlParams = new URLSearchParams(window.location.search);
  79. var skey = urlParams.get("skey");
  80. var path = window.location.pathname.split('/');
  81. var genId = path[path.length - 1];
  82. var onsuccess = function () {
  83. location.reload();
  84. clearInterval(refreshInterval);
  85. };
  86. var onblocked = function () {
  87. clearInterval(refreshInterval);
  88. errorImg[0].src = "https://r.bing.com/rp/in-2zU3AJUdkgFe7ZKv19yPBHVs.png";
  89. errorMsg[0].innerText = "Image was blocked";
  90. errorDesc[0].innerText = "";
  91. document.title = "(Blocked) " + document.title;
  92. };
  93. var onfailed = function () {
  94. useOldBehavior = true;
  95. };
  96. if (skey == null) {
  97. useOldBehavior = true;
  98. }
  99. refreshInterval = setInterval(() => {
  100. if (useOldBehavior) {
  101. oldBehavior();
  102. return;
  103. }
  104. checkEditStatus(skey, genId, onsuccess, onblocked, onfailed);
  105. }, 1000);
  106. }
  107.  
  108. function addQueryParamToResult() {
  109. var results = document.getElementsByClassName("single-img-link");
  110. for (var i = 0; i < results.length; i++) {
  111. var element = results[i];
  112. element.href = element.href + "&_dbe=1"
  113. }
  114. }
  115.  
  116. function update() {
  117. var iframe = document.getElementById('OverlayIFrame');
  118. isiframe = iframe != null;
  119. var frameElm = iframe ? iframe.contentWindow.document : window.document;
  120. var detailsElm = frameElm.getElementById("detailMeta");
  121. var imgd = frameElm.getElementById("msz");
  122. if (detailsElm != null && imgd != null && imgd.innerText != null) {
  123. clearInterval(t);
  124. console.log("stopped interval");
  125. t = null;
  126. // BIC returns error if we send an edit request for an image that was already edited so no point in showing the button
  127. if (imgd.innerText.startsWith("1024 × 1024")) {
  128. addButton(detailsElm);
  129. }
  130. }
  131. }
  132.  
  133. function addButton(detailsElm) {
  134. var main = detailsElm.getElementsByClassName("actn_container")[0];
  135. var bingWideContainer = document.createElement("div");
  136. var generateBtn = document.createElement("div");
  137. var buttonText = document.createElement("span");
  138. buttonText.setAttribute("id", "bingwidebuttontext");
  139. buttonText.setAttribute("style", "color: #953f00;font-weight:bold;font-size:17px;");
  140. buttonText.innerText = "Generate";
  141. generateBtn.setAttribute("class", "action nofocus");
  142. generateBtn.setAttribute("id", "bingwidebutton");
  143. generateBtn.setAttribute("style", "background-color:#fff0d3;display:inline-block;text-align:center;width:150px;margin-left:20px;");
  144. generateBtn.onclick = function () {
  145. // 2 seconds cooldowns to prevent accidental double clicks
  146. var now = performance.now();
  147. if (lastRegen + 2000 < now) {
  148. prepare();
  149. lastRegen = now;
  150. } else {
  151. console.log("blocked - cooldown");
  152. }
  153. };
  154. generateBtn.appendChild(buttonText);
  155. styleTb = document.createElement("input");
  156. styleTb.setAttribute("type", "text");
  157. styleTb.setAttribute("placeholder", "Enter custom style or leave empty to use default 'original'");
  158. styleTb.setAttribute("id", "bingwidestyle");
  159. styleTb.setAttribute("maxlength", "100");
  160. styleTb.setAttribute("spellcheck", "true");
  161. styleTb.setAttribute("list", "styleSuggestions");
  162. styleTb.setAttribute("style", "margin-top:15px;width: 440px;text-align: center;background-color: #fff0d3;color: #553030;font-weight: bold;font-size: 15px;");
  163. bingWideContainer.appendChild(styleTb);
  164. if (enableSuggestions) {
  165. var dl = document.createElement("datalist");
  166. dl.setAttribute("id", "styleSuggestions");
  167. for (var i = 0; i < styleSuggestions.length; i++) {
  168. var opt = document.createElement("option");
  169. opt.setAttribute("value", styleSuggestions[i]);
  170. dl.appendChild(opt);
  171. }
  172. bingWideContainer.appendChild(dl);
  173. }
  174. aspectRatioCb = document.createElement("select");
  175. aspectRatioCb.setAttribute("id", "bingwideaspectratio");
  176. aspectRatioCb.setAttribute("style", "margin-top:15px;background-color:#fdebca;font-weight:bold;font-size:13px;color:#953f00;");
  177. var aspectRatios = {
  178. "0": "Square (1024x1024)",
  179. "1": "Landscape (1792x1024)",
  180. "2": "Portrait (1024x1792)"
  181. }
  182. for (var x = 0; x < Object.keys(aspectRatios).length; x++) {
  183. var opt2 = document.createElement("option");
  184. opt2.setAttribute("value", Object.keys(aspectRatios)[x]);
  185. opt2.innerText = aspectRatios[x];
  186. aspectRatioCb.appendChild(opt2);
  187. }
  188. var br = document.createElement("br");
  189. var br2 = document.createElement("br");
  190. bingWideContainer.appendChild(br);
  191. bingWideContainer.appendChild(aspectRatioCb);
  192. bingWideContainer.appendChild(generateBtn);
  193. main.appendChild(bingWideContainer);
  194. (async() => {
  195. var lastUsedStyle = await GM.getValue("style", "original");
  196. var lastUsedAspectRatio = await GM.getValue("aspectratio", 1);
  197. if (lastUsedStyle != undefined && lastUsedStyle.toLowerCase() != "original") {
  198. styleTb.value = lastUsedStyle;
  199. }
  200. if (lastUsedAspectRatio >= 0 && lastUsedAspectRatio <= 2) {
  201. aspectRatioCb.children[lastUsedAspectRatio].setAttribute("selected", "selected");
  202. }
  203. var hideMessage = await GM.getValue("hideMessage1", false);
  204. if (hideMessage) {
  205. return;
  206. }
  207. var messageContainer = document.createElement("div");
  208. var spanMessage = document.createElement("span");
  209. spanMessage.setAttribute("style", "white-space:break-spaces;color:#f4d5d5;");
  210. var spanMessage2 = document.createElement("span");
  211. spanMessage2.setAttribute("style", "color:#eca26b;");
  212. var messageOkCb = document.createElement("input");
  213. messageOkCb.setAttribute("type", "checkbox");
  214. messageOkCb.setAttribute("name", "hideMessageCb");
  215. messageOkCb.setAttribute("id", "hideMessageCb");
  216. var messageLabel = document.createElement("label");
  217. messageLabel.setAttribute("for", "hideMessageCb");
  218. messageLabel.setAttribute("style", "color:#fdebca;display:inline;");
  219. messageLabel.innerText = "Hide this message permanently";
  220. spanMessage.innerHTML = "<br/>Style can be used to further fine-tune the image. I don't know the full potential of this but think of it as an additional prompt for post-production. There doesn't seems to be a word filter but the visual filter is still active.<br/>Edited generations are opened in a new tab. Make sure to allow popups from this page or the script might get blocked.<br/>";
  221. spanMessage2.innerHTML = "Each generation attempt still counts towards your account daily limit.";
  222. spanMessage.appendChild(spanMessage2);
  223. messageContainer.appendChild(spanMessage);
  224. messageContainer.appendChild(br2);
  225. messageContainer.appendChild(messageOkCb);
  226. messageContainer.appendChild(messageLabel);
  227. bingWideContainer.appendChild(messageContainer);
  228. messageOkCb.addEventListener('change', (event) => {
  229. if (event.currentTarget.checked) {
  230. GM.setValue("hideMessage1", true);
  231. bingWideContainer.removeChild(messageContainer);
  232. }
  233. });
  234. })();
  235. }
  236.  
  237. function prepare() {
  238. var params = new URLSearchParams(window.location.search);
  239. var querystrings = (isiframe ? unsafeWindow.document.getElementById("OverlayIFrame").contentWindow.window : unsafeWindow).ImageDetailReducers.g_PageConfig.persistedQueryStrings;
  240. var path = window.location.pathname.split('/');
  241. var genId = path[path.length - 1];
  242. var imgId = params.get("id");
  243. var skey = /skey=(.+?)&/.exec(querystrings)[1];
  244. var query = (isiframe ? unsafeWindow.document.getElementById("OverlayIFrame").contentWindow.document : unsafeWindow.document).getElementsByClassName("ptitle nolink")[0].innerText;
  245. if (imgId == null || imgId.length < 5 || skey == null || skey.length < 5) {
  246. alert("Something went wrong");
  247. return;
  248. }
  249. sendResizeRequest(encodeURIComponent(genId), encodeURIComponent(imgId), encodeURIComponent(skey), encodeURIComponent(query));
  250. }
  251.  
  252. function sendResizeRequest(genid, imgid, skey, query) {
  253. query = "a cat";
  254. var style = "original";
  255. var aspectratio = 1; //0 = square (1024x1024), 1 = landscape (1792x1024), 2 = portrait (1024x1792)
  256. if (styleTb != null && styleTb.value.length >= 3) {
  257. style = styleTb.value;
  258. }
  259. if (aspectRatioCb != null && aspectRatioCb.selectedIndex != -1) {
  260. aspectratio = aspectRatioCb.value;
  261. }
  262. console.log("Generating this image with an aspect ratio value of '" + aspectratio + "' with the style '" + style + "'.");
  263. GM.setValue("style", style);
  264. GM.setValue("aspectratio", aspectratio);
  265. GM.xmlHttpRequest({
  266. method: "POST",
  267. url: "/images/edit/resize?iid=" + imgid + "&skey=" + skey + "&id=" + genid + "&q=" + query + "&partner=Sydney&ar=" + aspectratio + "&s=" + style + "&rt=4",
  268. onload: function (response) {
  269. var jsonRes = JSON.parse(response.responseText);
  270. if (response.status == 200) {
  271. var urlSplit = jsonRes.webSearchUrl.split('/');
  272. window.open("/images/create/a-cat/" + urlSplit[urlSplit.length - 1] + "?_dbe=1&skey=" + skey, '_blank');
  273. } else if (jsonRes.errors[0].message.includes("InvalidOwner")) {
  274. alert("Request was unsuccessful. You are trying to edit an image that doesn't belongs to the current account you are using.");
  275. } else if (jsonRes.errors[0].code == ("RateLimitExceeded")) {
  276. alert("Request was unsuccessful. Your account exceeded rate limit.");
  277. } else {
  278. alert("Request was unsuccessful. Unknown error.");
  279. }
  280. },
  281. error: function (event) {
  282. alert("Couldn't send request.");
  283. }
  284. });
  285. }
  286.  
  287. function checkEditStatus(skey, genid, onsuccess, onblocked, onfailed) {
  288. GM.xmlHttpRequest({
  289. method: "GET",
  290. url: "/images/edit/poll?iid=ey%3D%3D&skey=" + skey + "&id=" + genid + "&q=a+cat&partner=Sydney",
  291. onload: function (response) {
  292. if (response.status == 404) {
  293. onfailed();
  294. return;
  295. }
  296. var jsonRes = JSON.parse(response.responseText);
  297. if (jsonRes._type == "RetrieveImagesResponse" && jsonRes.images != null && jsonRes.images.length > 0) {
  298. onsuccess();
  299. } else if (jsonRes._type == "ErrorResponse") {
  300. onblocked();
  301. }
  302. },
  303. error: function (event) {
  304. onfailed();
  305. }
  306. });
  307. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement