Spaces:
Runtime error
Runtime error
Update src/addons/addons/save-to-google/userscript.js
Browse files
src/addons/addons/save-to-google/userscript.js
CHANGED
@@ -14,7 +14,8 @@ export default async ({ addon, console, msg }) => {
|
|
14 |
const PROXY_URL = "https://soiz1-drive-proxy.hf.space/?file_id=";
|
15 |
const SHORT_URL = "https://s4.rf.gd/";
|
16 |
|
17 |
-
let accessToken = null;
|
|
|
18 |
|
19 |
while (true) {
|
20 |
const targetElem = await addon.tab.waitForElement(
|
@@ -37,24 +38,37 @@ export default async ({ addon, console, msg }) => {
|
|
37 |
}
|
38 |
|
39 |
function showMainModal(addon) {
|
40 |
-
const modal = addon.tab.createModal("Googleドライブに保存", {
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
modal.content.innerHTML = `
|
43 |
-
<div style="padding: 1rem;">
|
44 |
-
<h1>Googleドライブに接続</h1>
|
45 |
-
|
46 |
-
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
49 |
-
<h2 style="margin: 0;">プロジェクト: <span id="project-title" style="cursor: pointer; border-bottom: 1px dashed #000;">${window.vm.runtime.projectName || "無題"}</span></h2>
|
50 |
<button id="new-file-button" class="button">新規保存</button>
|
51 |
</div>
|
52 |
-
<div id="file-list" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(
|
53 |
</div>
|
54 |
</div>
|
55 |
`;
|
56 |
|
57 |
const loginButton = modal.content.querySelector("#google-login-button");
|
|
|
58 |
const fileListContainer = modal.content.querySelector("#file-list-container");
|
59 |
const fileList = modal.content.querySelector("#file-list");
|
60 |
const newFileButton = modal.content.querySelector("#new-file-button");
|
@@ -84,35 +98,22 @@ export default async ({ addon, console, msg }) => {
|
|
84 |
});
|
85 |
});
|
86 |
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
loginButton.style.display = "none";
|
94 |
-
|
95 |
-
fetchDriveFiles(accessToken)
|
96 |
-
.then(files => {
|
97 |
-
displayFileList(files, accessToken, modal, addon);
|
98 |
-
fileListContainer.style.display = "block";
|
99 |
-
})
|
100 |
-
.catch(error => {
|
101 |
-
console.error("ファイル一覧取得エラー:", error);
|
102 |
-
showAlert(addon, "error", "ファイル一覧の取得に失敗しました");
|
103 |
-
});
|
104 |
-
}
|
105 |
-
};
|
106 |
-
window.addEventListener("message", messageListener);
|
107 |
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
|
|
|
|
116 |
|
117 |
newFileButton?.addEventListener("click", async () => {
|
118 |
try {
|
@@ -123,10 +124,49 @@ export default async ({ addon, console, msg }) => {
|
|
123 |
}
|
124 |
});
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
modal.backdrop.addEventListener("click", modal.remove);
|
127 |
modal.closeButton.addEventListener("click", modal.remove);
|
128 |
}
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
async function fetchDriveFiles(accessToken) {
|
131 |
const response = await fetch("https://www.googleapis.com/drive/v3/files?q=(mimeType='application/x-scratch' or mimeType='image/png')", {
|
132 |
headers: {
|
@@ -169,11 +209,14 @@ export default async ({ addon, console, msg }) => {
|
|
169 |
fileItem.style.flexDirection = "column";
|
170 |
fileItem.style.gap = "0.75rem";
|
171 |
fileItem.style.background = "#fff";
|
|
|
172 |
|
173 |
// サムネイル表示
|
174 |
const thumbnailContainer = document.createElement("div");
|
175 |
thumbnailContainer.style.position = "relative";
|
176 |
thumbnailContainer.style.aspectRatio = "4/3";
|
|
|
|
|
177 |
|
178 |
if (thumbnail) {
|
179 |
const thumbnailImg = document.createElement("img");
|
@@ -181,7 +224,8 @@ export default async ({ addon, console, msg }) => {
|
|
181 |
thumbnailImg.style.width = "100%";
|
182 |
thumbnailImg.style.height = "100%";
|
183 |
thumbnailImg.style.borderRadius = "4px";
|
184 |
-
thumbnailImg.style.objectFit = "
|
|
|
185 |
thumbnailContainer.appendChild(thumbnailImg);
|
186 |
} else {
|
187 |
const thumbnailPlaceholder = document.createElement("div");
|
@@ -209,23 +253,28 @@ export default async ({ addon, console, msg }) => {
|
|
209 |
// 共有リンク
|
210 |
const linkContainer = document.createElement("div");
|
211 |
linkContainer.style.display = "flex";
|
212 |
-
linkContainer.style.
|
213 |
-
linkContainer.style.
|
214 |
-
linkContainer.style.
|
215 |
-
|
216 |
-
const
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
|
|
|
|
|
|
|
|
223 |
|
224 |
const copyButton = document.createElement("button");
|
225 |
-
copyButton.textContent = "
|
226 |
copyButton.className = "button";
|
227 |
copyButton.style.fontSize = "0.8em";
|
228 |
copyButton.style.padding = "0.2rem 0.5rem";
|
|
|
229 |
|
230 |
copyButton.addEventListener("click", (e) => {
|
231 |
e.stopPropagation();
|
@@ -234,7 +283,6 @@ export default async ({ addon, console, msg }) => {
|
|
234 |
.catch(() => showAlert(addon, "error", "リンクのコピーに失敗しました"));
|
235 |
});
|
236 |
|
237 |
-
linkContainer.appendChild(link);
|
238 |
linkContainer.appendChild(copyButton);
|
239 |
fileItem.appendChild(linkContainer);
|
240 |
|
|
|
14 |
const PROXY_URL = "https://soiz1-drive-proxy.hf.space/?file_id=";
|
15 |
const SHORT_URL = "https://s4.rf.gd/";
|
16 |
|
17 |
+
let accessToken = localStorage.getItem('googleDriveAccessToken') || null;
|
18 |
+
let currentAccountEmail = localStorage.getItem('googleDriveAccountEmail') || null;
|
19 |
|
20 |
while (true) {
|
21 |
const targetElem = await addon.tab.waitForElement(
|
|
|
38 |
}
|
39 |
|
40 |
function showMainModal(addon) {
|
41 |
+
const modal = addon.tab.createModal("Googleドライブに保存", {
|
42 |
+
isOpen: true,
|
43 |
+
useEditorClasses: true,
|
44 |
+
maxWidth: "800px",
|
45 |
+
maxHeight: "80vh"
|
46 |
+
});
|
47 |
|
48 |
modal.content.innerHTML = `
|
49 |
+
<div style="padding: 1rem; max-height: 70vh; overflow-y: auto;">
|
50 |
+
<h1 style="font-size: 1.5rem; margin-bottom: 1rem;">Googleドライブに接続</h1>
|
51 |
+
${accessToken ? `
|
52 |
+
<div style="margin-bottom: 1rem; display: flex; justify-content: space-between; align-items: center;">
|
53 |
+
<div>ログイン中: ${currentAccountEmail || 'Googleアカウント'}</div>
|
54 |
+
<button id="change-account-button" class="button" style="padding: 0.25rem 0.5rem; font-size: 0.9rem;">アカウントを変更</button>
|
55 |
+
</div>
|
56 |
+
` : `
|
57 |
+
<p style="margin-bottom: 1rem;">Googleでログインして、プロジェクトを保存または更新します。</p>
|
58 |
+
<button id="google-login-button" class="button">Googleでログイン</button>
|
59 |
+
`}
|
60 |
+
<div id="file-list-container" style="margin-top: 1rem; ${accessToken ? '' : 'display: none;'}">
|
61 |
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
62 |
+
<h2 style="margin: 0; font-size: 1.2rem;">プロジェクト: <span id="project-title" style="cursor: pointer; border-bottom: 1px dashed #000;">${window.vm.runtime.projectName || "無題"}</span></h2>
|
63 |
<button id="new-file-button" class="button">新規保存</button>
|
64 |
</div>
|
65 |
+
<div id="file-list" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1rem; margin-top: 1rem;"></div>
|
66 |
</div>
|
67 |
</div>
|
68 |
`;
|
69 |
|
70 |
const loginButton = modal.content.querySelector("#google-login-button");
|
71 |
+
const changeAccountButton = modal.content.querySelector("#change-account-button");
|
72 |
const fileListContainer = modal.content.querySelector("#file-list-container");
|
73 |
const fileList = modal.content.querySelector("#file-list");
|
74 |
const newFileButton = modal.content.querySelector("#new-file-button");
|
|
|
98 |
});
|
99 |
});
|
100 |
|
101 |
+
if (loginButton) {
|
102 |
+
loginButton.addEventListener("click", () => {
|
103 |
+
startGoogleLogin(modal, addon);
|
104 |
+
});
|
105 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
+
if (changeAccountButton) {
|
108 |
+
changeAccountButton.addEventListener("click", () => {
|
109 |
+
accessToken = null;
|
110 |
+
currentAccountEmail = null;
|
111 |
+
localStorage.removeItem('googleDriveAccessToken');
|
112 |
+
localStorage.removeItem('googleDriveAccountEmail');
|
113 |
+
showMainModal(addon);
|
114 |
+
modal.remove();
|
115 |
+
});
|
116 |
+
}
|
117 |
|
118 |
newFileButton?.addEventListener("click", async () => {
|
119 |
try {
|
|
|
124 |
}
|
125 |
});
|
126 |
|
127 |
+
if (accessToken) {
|
128 |
+
fetchDriveFiles(accessToken)
|
129 |
+
.then(files => {
|
130 |
+
displayFileList(files, accessToken, modal, addon);
|
131 |
+
fileListContainer.style.display = "block";
|
132 |
+
})
|
133 |
+
.catch(error => {
|
134 |
+
console.error("ファイル一覧取得エラー:", error);
|
135 |
+
showAlert(addon, "error", "ファイル一覧の取得に失敗しました");
|
136 |
+
});
|
137 |
+
}
|
138 |
+
|
139 |
modal.backdrop.addEventListener("click", modal.remove);
|
140 |
modal.closeButton.addEventListener("click", modal.remove);
|
141 |
}
|
142 |
|
143 |
+
function startGoogleLogin(modal, addon) {
|
144 |
+
const messageListener = (event) => {
|
145 |
+
if (event.origin === "https://soiz1-penguin-upload.hf.space" && event.data.token) {
|
146 |
+
window.removeEventListener("message", messageListener);
|
147 |
+
accessToken = event.data.token;
|
148 |
+
currentAccountEmail = event.data.email || null;
|
149 |
+
|
150 |
+
localStorage.setItem('googleDriveAccessToken', accessToken);
|
151 |
+
if (currentAccountEmail) {
|
152 |
+
localStorage.setItem('googleDriveAccountEmail', currentAccountEmail);
|
153 |
+
}
|
154 |
+
|
155 |
+
showMainModal(addon);
|
156 |
+
modal.remove();
|
157 |
+
}
|
158 |
+
};
|
159 |
+
window.addEventListener("message", messageListener);
|
160 |
+
|
161 |
+
const authUrl = `https://accounts.google.com/o/oauth2/auth?` +
|
162 |
+
`client_id=${CLIENT_ID}` +
|
163 |
+
`&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
|
164 |
+
`&response_type=token` +
|
165 |
+
`&scope=${encodeURIComponent(SCOPES)}`;
|
166 |
+
|
167 |
+
window.open(authUrl, "_blank", "width=500,height=600");
|
168 |
+
}
|
169 |
+
|
170 |
async function fetchDriveFiles(accessToken) {
|
171 |
const response = await fetch("https://www.googleapis.com/drive/v3/files?q=(mimeType='application/x-scratch' or mimeType='image/png')", {
|
172 |
headers: {
|
|
|
209 |
fileItem.style.flexDirection = "column";
|
210 |
fileItem.style.gap = "0.75rem";
|
211 |
fileItem.style.background = "#fff";
|
212 |
+
fileItem.style.height = "100%";
|
213 |
|
214 |
// サムネイル表示
|
215 |
const thumbnailContainer = document.createElement("div");
|
216 |
thumbnailContainer.style.position = "relative";
|
217 |
thumbnailContainer.style.aspectRatio = "4/3";
|
218 |
+
thumbnailContainer.style.maxHeight = "150px";
|
219 |
+
thumbnailContainer.style.overflow = "hidden";
|
220 |
|
221 |
if (thumbnail) {
|
222 |
const thumbnailImg = document.createElement("img");
|
|
|
224 |
thumbnailImg.style.width = "100%";
|
225 |
thumbnailImg.style.height = "100%";
|
226 |
thumbnailImg.style.borderRadius = "4px";
|
227 |
+
thumbnailImg.style.objectFit = "contain";
|
228 |
+
thumbnailImg.style.backgroundColor = "#f0f0f0";
|
229 |
thumbnailContainer.appendChild(thumbnailImg);
|
230 |
} else {
|
231 |
const thumbnailPlaceholder = document.createElement("div");
|
|
|
253 |
// 共有リンク
|
254 |
const linkContainer = document.createElement("div");
|
255 |
linkContainer.style.display = "flex";
|
256 |
+
linkContainer.style.flexDirection = "column";
|
257 |
+
linkContainer.style.gap = "0.25rem";
|
258 |
+
linkContainer.style.marginBottom = "0.5rem";
|
259 |
+
|
260 |
+
const linkLabel = document.createElement("div");
|
261 |
+
linkLabel.textContent = "共有リンク:";
|
262 |
+
linkLabel.style.fontSize = "0.8em";
|
263 |
+
linkLabel.style.color = "#666";
|
264 |
+
linkContainer.appendChild(linkLabel);
|
265 |
+
|
266 |
+
const linkUrl = document.createElement("div");
|
267 |
+
linkUrl.textContent = `${SHORT_URL}${project.id}`;
|
268 |
+
linkUrl.style.fontSize = "0.9em";
|
269 |
+
linkUrl.style.wordBreak = "break-all";
|
270 |
+
linkContainer.appendChild(linkUrl);
|
271 |
|
272 |
const copyButton = document.createElement("button");
|
273 |
+
copyButton.textContent = "リンクをコピー";
|
274 |
copyButton.className = "button";
|
275 |
copyButton.style.fontSize = "0.8em";
|
276 |
copyButton.style.padding = "0.2rem 0.5rem";
|
277 |
+
copyButton.style.width = "100%";
|
278 |
|
279 |
copyButton.addEventListener("click", (e) => {
|
280 |
e.stopPropagation();
|
|
|
283 |
.catch(() => showAlert(addon, "error", "リンクのコピーに失敗しました"));
|
284 |
});
|
285 |
|
|
|
286 |
linkContainer.appendChild(copyButton);
|
287 |
fileItem.appendChild(linkContainer);
|
288 |
|