Skip to content

Commit 6b91785

Browse files
committed
Fix saving to Google Drive + PiP for Instant Mode
1 parent 405c25c commit 6b91785

File tree

3 files changed

+119
-175
lines changed

3 files changed

+119
-175
lines changed

src/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "__MSG_extName__",
44
"description": "__MSG_extDesc__",
55
"default_locale": "en",
6-
"version": "4.0.3",
6+
"version": "4.0.4",
77
"background": {
88
"service_worker": "background.bundle.js"
99
},

src/pages/Background/drive/handleSaveToDrive.js

Lines changed: 117 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,18 @@ const findOrCreateScreenityFolder = async (token) => {
88
"Content-Type": "application/json",
99
});
1010

11-
// Try to find existing folder
1211
const query = encodeURIComponent(
1312
`name='Screenity' and mimeType='application/vnd.google-apps.folder' and trashed=false`
1413
);
14+
1515
const searchRes = await fetch(
1616
`https://www.googleapis.com/drive/v3/files?q=${query}&fields=files(id,name)`,
1717
{ headers }
1818
);
1919

2020
const result = await searchRes.json();
21-
if (result.files?.length) {
22-
return result.files[0].id; // Folder already exists
23-
}
21+
if (result.files?.length) return result.files[0].id;
2422

25-
// Otherwise, create the folder
2623
const createRes = await fetch(`https://www.googleapis.com/drive/v3/files`, {
2724
method: "POST",
2825
headers,
@@ -36,191 +33,138 @@ const findOrCreateScreenityFolder = async (token) => {
3633
return newFolder.id;
3734
};
3835

39-
const saveToDrive = async (videoBlob, fileName, sendResponse) => {
40-
async function getAuthTokenFromStorage() {
41-
return new Promise((resolve, reject) => {
42-
chrome.storage.local.get(["token"], async (result) => {
43-
if (chrome.runtime.lastError) {
44-
reject(new Error(chrome.runtime.lastError));
45-
} else {
46-
const token = result.token;
47-
if (!token || token === null) {
48-
// Token is not set, trigger sign-in
49-
const newToken = await signIn();
50-
if (!newToken || newToken === null) {
51-
// Sign-in failed, throw an error
52-
reject(new Error("Sign-in failed"));
53-
}
54-
resolve(newToken);
55-
} else {
56-
// Token is set, check if it has expired
57-
let payload;
58-
try {
59-
payload = JSON.parse(atob(token.split(".")[1]));
60-
} catch (err) {
61-
// Token is invalid, refresh it
62-
chrome.identity.getAuthToken(
63-
{ interactive: true },
64-
(newToken) => {
65-
if (chrome.runtime.lastError) {
66-
reject(new Error(chrome.runtime.lastError));
67-
} else {
68-
resolve(newToken);
69-
}
70-
}
71-
);
72-
return;
73-
}
74-
75-
const expirationTime = payload.exp * 1000; // Convert to milliseconds
76-
const currentTime = Date.now();
77-
if (currentTime >= expirationTime) {
78-
// Token has expired, refresh it
79-
chrome.identity.getAuthToken(
80-
{ interactive: true },
81-
(newToken) => {
82-
if (chrome.runtime.lastError) {
83-
reject(new Error(chrome.runtime.lastError));
84-
} else {
85-
resolve(newToken);
86-
}
87-
}
88-
);
89-
} else {
90-
// Token is still valid
91-
resolve(token);
92-
}
93-
}
94-
}
95-
});
96-
});
97-
}
98-
99-
return new Promise(async (resolve, reject) => {
100-
try {
101-
// Get the access token from Chrome storage
102-
let token = await getAuthTokenFromStorage();
103-
104-
if (!token || token === null) {
105-
throw new Error("Sign-in failed");
36+
const getAuthTokenFromStorage = async () => {
37+
return new Promise((resolve, reject) => {
38+
chrome.storage.local.get(["token"], async (result) => {
39+
if (chrome.runtime.lastError) {
40+
reject(new Error(chrome.runtime.lastError));
41+
return;
10642
}
10743

108-
// Upload the video to Google Drive
109-
const headers = new Headers({
110-
Authorization: `Bearer ${token}`,
111-
"Content-Type": videoBlob.type,
112-
});
113-
114-
const uploadResponse = await fetch(
115-
"https://www.googleapis.com/upload/drive/v3/files?uploadType=media",
116-
{
117-
method: "POST",
118-
headers,
119-
body: videoBlob,
120-
}
121-
);
122-
123-
if (!uploadResponse.ok) {
124-
throw new Error(
125-
`Error uploading to Google Drive: ${uploadResponse.status}`
126-
);
44+
const token = result.token;
45+
if (!token) {
46+
const newToken = await signIn();
47+
if (!newToken) reject(new Error("Sign-in failed"));
48+
else resolve(newToken);
49+
return;
12750
}
12851

129-
const responseData = await uploadResponse.json();
130-
const fileId = responseData.id;
131-
132-
if (!fileId) {
133-
throw new Error("File ID is undefined");
52+
let payload;
53+
try {
54+
payload = JSON.parse(atob(token.split(".")[1]));
55+
} catch {
56+
chrome.identity.getAuthToken({ interactive: true }, (newToken) => {
57+
if (chrome.runtime.lastError)
58+
reject(new Error(chrome.runtime.lastError));
59+
else resolve(newToken);
60+
});
61+
return;
13462
}
13563

136-
// Create the metadata for the file
137-
const folderId = await findOrCreateScreenityFolder(token);
138-
const fileMetadata = {
139-
name: fileName,
140-
parents: [folderId],
141-
};
142-
143-
// Update the file metadata with the name
144-
const metadataResponse = await fetch(
145-
`https://www.googleapis.com/drive/v3/files/${fileId}`,
146-
{
147-
method: "PATCH",
148-
headers: new Headers({
149-
Authorization: `Bearer ${token}`,
150-
"Content-Type": "application/json; charset=UTF-8",
151-
}),
152-
body: JSON.stringify(fileMetadata),
153-
}
154-
);
155-
156-
if (!metadataResponse.ok) {
157-
const errorResponse = await metadataResponse.json();
158-
console.error(
159-
"Error updating file metadata:",
160-
metadataResponse.status,
161-
errorResponse.error.message
162-
);
163-
throw new Error(
164-
`Error updating file metadata: ${metadataResponse.status}`
165-
);
64+
const exp = payload.exp * 1000;
65+
if (Date.now() >= exp) {
66+
chrome.identity.getAuthToken({ interactive: true }, (newToken) => {
67+
if (chrome.runtime.lastError)
68+
reject(new Error(chrome.runtime.lastError));
69+
else resolve(newToken);
70+
});
71+
} else {
72+
resolve(token);
16673
}
167-
sendResponse({ status: "ok", url: fileId });
168-
169-
// Open the Google Drive file in a new tab
170-
chrome.tabs.create({
171-
url: `https://drive.google.com/file/d/${fileId}/view`,
172-
});
173-
174-
resolve(`https://drive.google.com/file/d/${fileId}/view`); // Return the file ID if needed
175-
} catch (error) {
176-
console.error("Error uploading to Google Drive:", error.message);
177-
sendResponse({ status: "ew", url: null });
178-
reject(error);
179-
}
74+
});
18075
});
18176
};
18277

78+
const saveToDrive = async (videoBlob, fileName) => {
79+
try {
80+
const token = await getAuthTokenFromStorage();
81+
if (!token) throw new Error("Sign-in failed");
82+
83+
// Upload the raw media
84+
const uploadResponse = await fetch(
85+
"https://www.googleapis.com/upload/drive/v3/files?uploadType=media",
86+
{
87+
method: "POST",
88+
headers: {
89+
Authorization: `Bearer ${token}`,
90+
"Content-Type": videoBlob.type,
91+
},
92+
body: videoBlob,
93+
}
94+
);
95+
96+
if (!uploadResponse.ok)
97+
throw new Error(`Upload failed: ${uploadResponse.status}`);
98+
99+
const { id: fileId } = await uploadResponse.json();
100+
if (!fileId) throw new Error("File ID is undefined");
101+
102+
// Add metadata and move to folder
103+
const folderId = await findOrCreateScreenityFolder(token);
104+
const metadataResponse = await fetch(
105+
`https://www.googleapis.com/drive/v3/files/${fileId}`,
106+
{
107+
method: "PATCH",
108+
headers: {
109+
Authorization: `Bearer ${token}`,
110+
"Content-Type": "application/json; charset=UTF-8",
111+
},
112+
body: JSON.stringify({
113+
name: fileName,
114+
parents: [folderId],
115+
}),
116+
}
117+
);
118+
119+
if (!metadataResponse.ok)
120+
throw new Error(`Metadata update failed: ${metadataResponse.status}`);
121+
122+
// Open the file in Drive
123+
chrome.tabs.create({
124+
url: `https://drive.google.com/file/d/${fileId}/view`,
125+
});
126+
127+
return { status: "ok", url: fileId };
128+
} catch (error) {
129+
console.error("Error uploading to Google Drive:", error.message);
130+
return { status: "ew", url: null };
131+
}
132+
};
133+
183134
const savedToDrive = async () => {
184135
const { sandboxTab } = await chrome.storage.local.get(["sandboxTab"]);
185136
sendMessageTab(sandboxTab, { type: "saved-to-drive" });
186137
};
187138

188-
export const handleSaveToDrive = async (
189-
sendResponse,
190-
request,
191-
fallback = false
192-
) => {
193-
if (!fallback) {
194-
const blob = base64ToUint8Array(request.base64);
195-
196-
const fileName = request.title + ".mp4";
197-
198-
saveToDrive(blob, fileName, sendResponse).then(() => {
199-
savedToDrive();
200-
});
201-
} else {
202-
const chunks = [];
203-
await chunksStore.iterate((value, key) => {
204-
chunks.push(value);
205-
});
206-
207-
// Build the video from chunks
208-
let array = [];
209-
let lastTimestamp = 0;
210-
for (const chunk of chunks) {
211-
// Check if chunk timestamp is smaller than last timestamp, if so, skip
212-
if (chunk.timestamp < lastTimestamp) {
213-
continue;
139+
export const handleSaveToDrive = async (request, fallback = false) => {
140+
try {
141+
let response;
142+
143+
if (!fallback) {
144+
const blob = base64ToUint8Array(request.base64);
145+
const fileName = request.title + ".mp4";
146+
response = await saveToDrive(blob, fileName);
147+
} else {
148+
const chunks = [];
149+
await chunksStore.iterate((value) => chunks.push(value));
150+
151+
let array = [];
152+
let lastTimestamp = 0;
153+
for (const chunk of chunks) {
154+
if (chunk.timestamp < lastTimestamp) continue;
155+
lastTimestamp = chunk.timestamp;
156+
array.push(chunk.chunk);
214157
}
215-
lastTimestamp = chunk.timestamp;
216-
array.push(chunk.chunk);
217-
}
218-
const blob = new Blob(array, { type: "video/webm" });
219158

220-
const filename = request.title + ".webm";
159+
const blob = new Blob(array, { type: "video/webm" });
160+
const fileName = request.title + ".webm";
161+
response = await saveToDrive(blob, fileName);
162+
}
221163

222-
saveToDrive(blob, filename, sendResponse).then(() => {
223-
savedToDrive();
224-
});
164+
await savedToDrive();
165+
return response;
166+
} catch (err) {
167+
console.error("handleSaveToDrive failed:", err);
168+
return { status: "ew", url: null };
225169
}
226170
};

src/pages/Camera/utils/cameraUtils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export const surfaceHandler = async (request, videoRef) => {
181181

182182
const shouldEnterPip =
183183
(request.surface === "monitor" && (!isSubscribed || instantMode)) ||
184-
(request.surface !== "monitor" && (isSubscribed || instantMode));
184+
(request.surface !== "monitor" && isSubscribed && !instantMode);
185185

186186
if (shouldEnterPip && videoRef.current) {
187187
await videoRef.current.requestPictureInPicture();

0 commit comments

Comments
 (0)