How do I download information stored in my Chrome extension? - google-chrome

I am developing a Chrome extension where the workflow looks like:
user browses the internet and can save links. I have a strong preferences to store all links locally instead of, say, having to talk to an external server.
user can then hit a button in the extension which generates and downloads a csv file of all the saved links so far
Two questions:
What is the appropriate way to store this data over multiple sessions?
What is the appropriate way of generating the file and prompting a download?
For 1, I plan on using chrome.storage.local.
For 2, it's unclear what the best way is. I'm considering writing the data to options.html or popup.html, then calling chrome.downloads to download that page, but it feels like a massive hack.
What is the correct way of doing 1 and 2?

Using chrome.storage.local is the right way here.
I am using this snippet right from the popup in order to save text/json/csv files:
/**
* #param data {String} what to save
* #param extension {String} file extension
*/
function saveFile(data, extension = 'json') {
const fileName = `export-file.${extension}`;
const textFileAsBlob = new Blob([data], {type: 'text/plain'});
const downloadLink = document.createElement('a');
downloadLink.download = fileName;
downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
downloadLink.target = '_blank';
downloadLink.click();
return fileName;
}
It will save a file to disk. And it is not a hacky way.
Update for #2
Another way is to pass base64 URL to the downloads API:
chrome.downloads.download({url: 'data:image/gif;base64,SEVMTE8gV09STEQh', filename: 'test.txt'})

Related

Export Google document as a string representation, then import it back (has to end up identical)

I'm looking for a way to programmatically export a Google Document, to be able to re-import it later, exactly as it was in the first place.
DriveApp.getFileById(file.id).makeCopy(filename) won't do the job since I need to send the document to an external server between export and re-import.
const file = DriveApp.getFileById(item.id);
const blob = file.getBlob(); // <- This line seems to convert the doc to pdf
const blobStr = blob.getDataAsString();
// Then later...
const newBlob = Utilities.newBlob(blobStr, blob.getContentType(), `COPY OF ${item.title}`);
const newFile = DriveApp.createFile(newBlob); // Create a new file from a blob
My problem here is that file.getBlob() converts the document to pdf. Which I don't want. I need it to still be a Google Document when I create the file.
Am I missing something ? maybe Google documents can't be represented as a string or byte at all...?
To give a little bit of context, I'm sending the document for translation to an external service. When translated strings come back, I need to map them back into the original document keeping the formatting and everything exactly as it was.

Snapchat download all memories at once

Over the years on snapchat I have saved lots of photos that I would like to retrieve now, The problem is they do not make it easy to export, but luckily if you go online you can request all the data (thats great)
I can see all my photos download link and using the local HTML file if I click download it starts downloading.
Here's where the tricky part is, I have around 15,000 downloads I need to do and manually clicking each individual one will take ages, I've tried extracting all of the links through the download button and this creates lots of Urls (Great) but the problem is, if you past the url into the browser then ("Error: HTTP method GET is not supported by this URL") appears.
I've tried a multitude of different chrome extensions and none of them show the actually download, just the HTML which is on the left-hand side.
The download button is a clickable link that just starts the download in the tab. It belongs under Href A
I'm trying to figure out what the best way of bulk downloading each of these individual files is.
So, I just watched their code by downloading my own memories. They use a custom JavaScript function to download your data (a POST request with ID's in the body).
You can replicate this request, but you can also just use their method.
Open your console and use downloadMemories(<url>)
Or if you don't have the urls you can retrieve them yourself:
var links = document.getElementsByTagName("table")[0].getElementsByTagName("a");
eval(links[0].href);
UPDATE
I made a script for this:
https://github.com/ToTheMax/Snapchat-All-Memories-Downloader
Using the .json file you can download them one by one with python:
req = requests.post(url, allow_redirects=True)
response = req.text
file = requests.get(response)
Then get the correct extension and the date:
day = date.split(" ")[0]
time = date.split(" ")[1].replace(':', '-')
filename = f'memories/{day}_{time}.mp4' if type == 'VIDEO' else f'memories/{day}_{time}.jpg'
And then write it to file:
with open(filename, 'wb') as f:
f.write(file.content)
I've made a bot to download all memories.
You can download it here
It doesn't require any additional installation, just place the memories_history.json file in the same directory and run it. It skips the files that have already been downloaded.
Short answer
Download a desktop application that automates this process.
Visit downloadmysnapchatmemories.com to download the app. You can watch this tutorial guiding you through the entire process.
In short, the app reads the memories_history.json file provided by Snapchat and downloads each of the memories to your computer.
App source code
Long answer (How the app described above works)
We can iterate over each of the memories within the memories_history.json file found in your data download from Snapchat.
For each memory, we make a POST request to the URL stored as the memories Download Link. The response will be a URL to the file itself.
Then, we can make a GET request to the returned URL to retrieve the file.
Example
Here is a simplified example of fetching and downloading a single memory using NodeJS:
Let's say we have the following memory stored in fakeMemory.json:
{
"Date": "2022-01-26 12:00:00 UTC",
"Media Type": "Image",
"Download Link": "https://app.snapchat.com/..."
}
We can do the following:
// import required libraries
const fetch = require('node-fetch'); // Needed for making fetch requests
const fs = require('fs'); // Needed for writing to filesystem
const memory = JSON.parse(fs.readFileSync('fakeMemory.json'));
const response = await fetch(memory['Download Link'], { method: 'POST' });
const url = await response.text(); // returns URL to file
// We can now use the `url` to download the file.
const download = await fetch(url, { method: 'GET' });
const fileName = 'memory.jpg'; // file name we want this saved as
const fileData = download.body; // contents of the file
// Write the contents of the file to this computer using Node's file system
const fileStream = fs.createWriteStream(fileName);
fileData.pipe(fileStream);
fileStream.on('finish', () => {
console.log('memory successfully downloaded as memory.jpg');
});

firebase Google Cloud storage download URL has folder name which becomes file name

We are using Firebase Google Cloud Storage Bucket to store our files.
When the logged in user wants the download the file kept inside certain folder
Eg: 123/admin/1469611803143/123.xlsx
The url generated will be
https://firebasestorage.googleapis.com/v0/b/MYWEBSITE.appspot.com/o/123%2Fadmin%2F1469611803143%2F123.xlsx?alt=media&token=whatever_alpa_numeric_token
As I download this file the file name will be 123%2Fadmin%2F1469611803143%2F123.xlsx
and not 123.xlsx
We have tried using download attribute to change the file name
but this did not change the file name to 123.xlsx
Please HELP
I'm pretty new with firebase but I achieved this with the following code :
var storageRef = firebase.storage().ref();
var child = storageRef.child("your path");
var uploadTask = child.put(<file>);
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
function(snapshot){
// HANDLE TASK PROGRESS
},
function(error){
// HANDLE ERROR
},
function(){
// UPLOAD SUCCESSFULL
var newMetadata = {
contentDisposition : "attachment; filename=" + fileName
}
child.updateMetadata(newMetadata)
})
This is (fortunately or unfortunately) intended behavior. Technically, files in Firebase Storage are stored with the full path (so 123%2Fadmin%2F1469611803143%2F123.xlsx is actually the file name--the slashes and percent escaping are part of the name, and are only represented as path separators in the UI), which is how we get this behavior.
We're likely to modify how downloads work in the future (in that we'll truncate the name), but we've been busy fixing other bugs and polishing higher priority pieces.

Edit on Google Docs without converting

I'm integrating my system with Google Drive. Everything is working so far, but one thing. I cannot edit the uploaded Word documents without converting them to Google Docs first.
I've read here it's possible using a Chrome plugin:
https://support.google.com/docs/answer/6055139?hl=en
But that's not my goal. I'm storing the file's information on my database and then I just request the proper URL for editing and previewing. Previewing is working fine, but when I try the edit URL it says the file does not exist. If I convert the file (using Google Drive's interface) and pass the new ID it works. I don't want to convert the user's documents to Google Drive because they still use Word as their main editing software.
Is there a way to accomplish this?
This is how I'm doing right now:
public static File UploadFile(FileInfo fileInfo, Stream stream, string googleAccount)
{
var mimetype = GetValidMimetype(fileInfo.MimeType);
var parentFolder = GetParentFolder(fileInfo);
var file = new File { Title = fileInfo.Title, MimeType = mimetype, Parents = parentFolder };
var uploadRequest = _service.Files.Insert(file, stream, mimetype);
uploadRequest.Upload();
file = uploadRequest.ResponseBody;
ShareFileWith(file.Id, googleAccount);
return file;
}
This is the URL for editing (where {0} is the file ID):
https://docs.google.com/document/d/{0}/edit?usp=drivesdk
I know that in order to convert the file I just need to:
uploadRequest.Convert = true;
But again, that's not what I want. Is it possible?
Thanks!
EDIT
Just an update. Convert = true should've worked but it's not. I've raised an issue for that here https://github.com/google/google-api-dotnet-client/issues/712
Bottomline, it only works if I open the file on Google Docs and then use its Id...

StorageFile - gaining access to image outside LocalStorage

Is it possible in WinRT to gain access to image file outside LocalStorage such that I could use file URI to bind it to source property in Image control? I can't use .OpenRead() with storing files in memory because I could have too many images (possible OutOfMemoryException). I also can't control my container rendering behaviour - it's FlipView and it doesn't have anything like ContainerContentChanging event in GridView (as far as I know).
Unless your image files are in the pictures library and your app declares the "Pictures Library" capability in its manifest - you will need to ask the user for permission to access these files by using a file or folder picker. You can then save the token that allows access to that file/folder in the future access list.
One article I found that describes this gives these quick snippets:
To save token
var picker = new FolderPicker();
picker.FileTypeFilter.Add("*");
var folder = await picker.PickSingleFolderAsync();
StorageApplicationPermissions.FutureAccessList.AddOrReplace(Token, folder);
To access a storage item unlocked by a token
var folder = await StorageApplicationPermissions
.FutureAccessList.GetFolderAsync(Token);
var fileToCopy = await StorageFile
.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Logo.png"));
await fileToCopy.CopyAsync(folder, "Logo.png", NameCollisionOption.ReplaceExisting);
You could possibly use the file/folder path as a token if you need to enable more of these.