Storing Data in firebase using VBA - firebase

Is there any way to upload files using VBA to firebase?
Web code for uploading files in firebase
var storageRef = firebase.storage.ref("folderName/file.jpg");
var fileUpload = document.getElementById("fileUpload");
fileUpload.on(‘change’, function(evt) {
var firstFile = evt.target.file[0]; // get the first file uploaded
var uploadTask = storageRef.put(firstFile);
uploadTask.on(‘state_changed’, function progress(snapshot) {
console.log(snapshot.totalBytesTransferred); // progress of upload
});
});
But how do I use this in VBA? any help is appreciated. Also if you can point to me in right direction.

I did some research on Firebase. Currently you cannot use VBA to upload files directly to FB Storage, through API.
You can try using JS, as mentioned by you.
Another alternative will be Google Cloud Storage. Which is the back-end for firebase storage.

two ways of doing this.. Assuming there is a website where you can upload files, in such case you can use the standard IE object to navigate to a specific website, find the controls, select the files and using submit or click function upload the file..
The other way is to write a web-service and call it from vba. Both suggestions involves in calling the website/service.
Dim IE As Object
Set IE = CreateObject("internetexplorer.application")
IE.Navigate "Your upload page.."
Do While IE.ReadyState <> 4 Or IE.Busy = True
DoEvents
Loop
we don't have enough information so I just continue with the logic.
Find the upload document/filename field. insert your filename
IE.Document.getElementById("txt_upload_field").Value = myFileName
find the button/element to upload and perform click/submit action.
wait for your website and read the result
or you can write your own web service and perform a web-request using XMLHTTP. I personally would go for web-service.
there is also a third way. FTPing to your server..!

Related

Linking images from Firebase Storage to Firestore document and displaying them in React Native

Background
I'm trying to upload images to firebase storage manually (using the upload file button in the web page), however I have no clue how to later link them to a firestore document. What I have come up with (I'm unsure if it works) is copying the url for the image in the storage bucket and adding it to a string type field in the document called profilePicture. The reason I'm unable to get this to work is that I'm really new to React Native and I don't know how to properly require the images other than typing in the specific local route. Mind you also, the way I'm requiring user data such as a profile name is after logging in with email/password auth I pass the data as a param to react navigation and require it as extraData.
What I have tried
Once I've copied the image url and pasted it in the firestore document I'm doing this:
const profilePicture = props.extraData.profilePicture;
<Image source={require({profilePicture})}/>
I have also tried using backticks but that isn't working either. The error message I'm getting is:
TransformError src\screens\Profile\ProfileScreen.js: src\screens\Profile\ProfileScreen.js:Invalid call at line 27: require({
profilePicture: profilePicture
})
Note: this is an expo managed project.
Question
Is the problem in the code or in the way I'm linking both images? Maybe both? Should I require the document rather than relying on the data passed previously?
Thanks a lot in advance!
Edit 1:
I'm trying to get all info from the current user signed in, after a little research I've come to know about requiring images in this manner:
const ref = firebase.storage().ref('path/to/image.jpg');
const url = await ref.getDownloadURL();
and then I'd require the image as in <Image source={{uri: url}}/>
I get that this could be useful for something static, but I don't get how to update the ref for every single different user.
Edit 2:
Tried using the method mentioned in Edit 1, just to see what would happen, however It doesn't seem to work, the image just does not show up.
Maybe because my component is a function component rather than a class component (?
I understand that your goal is to generate, for each image that is uploaded to Cloud Storage, a Firestore document which contains a download URL.
If this is correct, one way is to use a Cloud Function that is triggered each time a new file is added to Cloud Storage. The following Cloud Function code does exactly that. You may adapt it to your exact requirements.
exports.generateFileURL = functions.storage.object().onFinalize(async object => {
try {
const bucket = admin.storage().bucket(object.bucket);
const file = bucket.file(object.name);
// You can check that the file is an image
const signedURLconfig = { action: 'read', expires: '08-12-2025' }; // Adapt as follows
const signedURLArray = await file.getSignedUrl(signedURLconfig);
const url = signedURLArray[0];
await admin.firestore().collection('profilePictures').add({ fileName: object.name, signedURL: url }) // Adapt the fields list as desired
return null;
} catch (error) {
console.log(error);
return null;
}
});
More info on the getSignedUrl() method of the Admin SDK here.
Also note that you could assign the Firestore document ID yourself, instead of having Firestore generating it as shown in the above code (with the add() method). For example, you can add to the image metadata the uid of the user and, in the Cloud Function,get this value and use this value as the Document ID.
Another possibility is to name the profile image with the user's uid.

Firebase: Is it possible to stream a video? [duplicate]

I'm working on an app that has video streaming functionality. I'm using firebase database and firebase storage. I'm trying to find some documentation on how firebase storage handles video files, but can't really find much.
There's mentioning in the docs that firebase storage works with other google app services to allow for CDN and video streaming, but all searches seem to lead to a dead end. Any advice?
I think there are several types of video streaming, which could change our answer here:
Live streaming (subscribers are watching as an event happens)
Youtube style (post a video and end users watch at their convenience)
Having built a live streaming Periscope style app using Firebase Storage and the Firebase Realtime Database, I pretty strongly recommend against it--we uploaded three second chunks and synced them via the Realtime Database. While it worked (surprisingly well), there was ~5 second latency over very good internet, and it also wasn't the most efficient solution (after all, you're uploading and storing that video, plus there wasn't any transcoding). I recommend using some WebRTC style, built for video transport, and using the Realtime Database for signaling along side the stream.
On the other side, it's definitely possible to build mobile YT on Firebase features. The trick here is going to be transcoding the video (using something like Zencoder or Bitmovin, more here: https://cloud.google.com/solutions/media/) to chop up your uploaded video into smaller chunks of different resolutions (and different formats, iOS requires HLS for streaming, for instance). You client can store chunk information in the Realtime Database (chunk name, resolutions available, number of chunks), and can download said chunks from Storage as the video progresses.
If you want to steam a video from Firebase Storage, this is the best way I found. This will depend on the size of your video file. I'm only requesting 10-30mb files so this solution works good for me. Just treat the Firebase Url as a regular url:
String str = "fire_base_video_URL";
Uri uri = Uri.parse(str);
videoViewLandscape.setVideoURI(uri);
progressBarLandScape.setVisibility(View.VISIBLE);
videoViewLandscape.requestFocus();
videoViewLandscape.start();
If you want to loop the video:
videoViewLandscape.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
}
});
And if you want to show a progress bar before the video starts do this:
videoViewLandscape.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
progressBarLandScape.setVisibility(View.GONE);
return true;
}
else if(what == MediaPlayer.MEDIA_INFO_BUFFERING_START){
progressBarLandScape.setVisibility(View.VISIBLE);
return true;
}
return false;
}
});
This is not the best way of doing things but it works for me for now until I can find a good video streaming service.
2020: Yes, firebase storage video streaming is easy and possible.
All other questions suggest that you use a protocol like HLS. However, this is only necessary if you develop an app for the Apple AppStore that serves videos that are longer than 10 minutes.
In all other cases, you can simply encode your videos in mp4 and upload them to firebase. Your clients can then stream the mp4 without a problem. Just make sure that your moov atom is at the beginning of your mp4 file. This allows to start playing the video immediately, even if it is not fully loaded.
Users can also skip ahead or go back thanks to variable bit requests which are supported by firebase storage.
To test it, just upload a video to your firebase storage and open it in your browser.
You can host HLS videos on Firebase Cloud Storage. It works pretty well for me.
The trick is to modify the playlist .m3u8 files to contain the storage folder prefix, and the ?alt=media suffix for each file entry in the playlist:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:2.760000,
<folder_name>%2F1_fileSequence_0.ts?alt=media
#EXT-X-ENDLIST
You also don't really have to use server-side transcoding, you can have the client who uploads the video do it, and save considerable costs.
I've written a full tutorial with source code here: https://itnext.io/how-to-make-a-serverless-flutter-video-sharing-app-with-firebase-storage-including-hls-and-411e4fff68fa
this is my exact implementation for it to start a video playing from storage on firebase as soon as the view is open, and then have the view disappear and then addded a button to click after to replay the video.
I have a demo link with the key so you can see it works. any questions hit me up.
you will just have to create a IBAction if you want the button after the video disappears.
// BackMuscles.swift
// Messenger
//
// Created by Zach Smith on 8/12/21.
// Copyright © 2021 spaceMuleFitness. All rights reserved.
//
import UIKit
import AVKit
import AVFoundation
class BackMuscles: UIViewController {
#IBOutlet weak var playv: UIButton!
let avPlayerViewController = AVPlayerViewController()
var avPlayer:AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
self.view.addBackground()
let movieUrl:NSURL? = NSURL(string: "https://firebasestorage.googleapis.com/v0/b/messenger-test-d225b.appspot.com/o/test%2FTestVideo.mov?alt=media&token=bd4ccba3-b446-43bc-809e-b1152aa3c2ff")
if let url = movieUrl {
self.avPlayer = AVPlayer(url: url as URL)
self.avPlayerViewController.player = self.avPlayer
}
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: avPlayerViewController.player?.currentItem)
self.present(self.avPlayerViewController, animated: true) { () -> Void in
self.avPlayerViewController.player?.play() // Do any additional setup after loading the view.
}
}
#objc func playerDidFinishPlaying(note: NSNotification) {
self.avPlayerViewController.dismiss(animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func playV(sender: UIButton) {
let amovieUrl:NSURL? = NSURL(string: "https://firebasestorage.googleapis.com/v0/b/messenger-test-d225b.appspot.com/o/test%2FTestVideo.mov?alt=media&token=bd4ccba3-b446-43bc-809e-b1152aa3c2ff")
if let aurl = amovieUrl {
self.avPlayer = AVPlayer(url: aurl as URL)
self.avPlayerViewController.player = self.avPlayer
self.present(self.avPlayerViewController, animated: true) { () -> Void in
self.avPlayerViewController.player?.play()
}
}
}
}
If you want to create a YT like app, you can first compress the video, I recommend using this library to manage video compression, i recommend the one in this link. I've manage to compress a video of 118 mg to 6 mg in under 42 seconds. It also has a great demo app, just follow the example.
After you get the compressed file upload the file to Storage, in you client app you will play the video url using a player like Exo Player.
The video below is pretty good it uses exoplayer to stream instead of mediaplayer or videoViewLanscape
https://www.youtube.com/watch?v=s_D5C5e2Uu0
try{
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(bandwidthMeter));
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
String vid = "https://www.youtube.com/watch?v=s_D5C5e2Uu0";
Uri uri= Uri.parse(vid);
DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("exoplayer_video");
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(uri,dataSourceFactory,
extractorsFactory, null, null);
videoView.setPlayer(simpleExoPlayer);
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(true);
}
catch (Exception e){
}
The below is the implements in the buid gradle app file that you will need.
implementation 'com.google.android.exoplayer:exoplayer:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-hls:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-ui:r2.4.0'
To use firestorage to play videos, all you need is the full url to the video. You then pass this url into a video view or exoplayer. No full download is needed. The videoview will stream the content YT style
see first of all you need to understand firebase rules okay
like make it true for development mode
then you have to create a storage reference for storing videos in your app
okay
then you have to select video you want to upload okay
then use Uploadtask for creating a task
and upload video file in storage
now for retrieving video use exoplayer library in android
you can visit here for more

Is there a way of saving a Google Doc so it has the same unique ID as an existing doc?

I have a need to create a copy of a Google Doc with a specific ID - not the "friendly" name like MyDocument, but the name that makes it unique in the GoogleSphere - the one like 1x_tfTiA9-b5UwAf3k2fg6y6hyZSYQIvhSNn-saaDs4c.
Here's the scenario why I would like to do this:
I have a newsletter which is in the form of a Google Doc. The newsletter is published on a website by embedding the document in a web page inside an <iframe> element. Also published in the same way is a "large print" version of the newsletter that is the same, apart from the fact that the default font size is 24pt, rather than 11pt.
I am trying to automate the production of the large print version, but in such a way that the unique ID of the large print document doesn't change, so that the embedded <iframe> for it still works.
I have experimented in the past with Google Apps Scripts routines for creating a deep copy of a document but the deep copy functions don't play nicely with images and tables, so I could never get a complete copy. If I could implement a "Save As" function, where the operand was an existing unique ID, I think this would do what I want.
Anyone know how I might do this?
I delved into this, attempting to set the id of the "large print" version of the file in a variety of ways:
via copy(): var copiedFile = Drive.Files.copy(lpFile, spFile.id, options);
which yields the error:
Generated IDs are not currently supported for copy requests
via insert(): var newFile = Drive.Files.insert(lpFile, doc.getBlob(), options);
which yields the error:
Generated IDs are not supported for Google Docs formats
via update(): Drive.Files.update(lpFile, lpFile.id, doc.getBlob(), options);
This method successfully updates the "large print" file from the small print file. This particular line, however, uses the Document#getBlob() method, which has issues with formatting and rich content from the Document. In particular, as you mention, images and tables in are not preserved (among other things, like changes to the font, etc.). Compare pre with post
It seems that - if the appropriate method of exporting formatted byte content from the document can be found - the update() method has the most promise. Note that the update() method in the Apps Script client library requires a Blob input (i.e. doc.getBlob().getBytes() will not work), so the fundamental limitation may be the (lack of) support for rich format information in the produced Blob data. With this in mind, I tried a couple methods for obtaining "formatted" Blob data from the "small print" file:
via Document#getAs(mimetype): Drive.Files.export(lpFile, lpFile.id, doc.getAs(<type>), options);
which fails for seemingly sensible types with the errors:
MimeType.GOOGLE_DOCS: We're sorry, a server error occurred. Please wait a bit and try again.
MimeType.MICROSOFT_WORD: Converting from application/vnd.google-apps.document to application/vnd.openxmlformats-officedocument.wordprocessingml.document is not supported.
These errors do make sense, since the internal Google Docs MimeType is not exportable (you can't "download as" this filetype since the data is kept however Google wants to keep it), and the documentation for Document#getAs(mimeType) indicates that only PDF export is supported by the Document Service. Indeed, attempting to coerce the Blob from doc.getBlob() with getAs(mimeType) fails, with the error:
Converting from application/pdf to application/vnd.openxmlformats-officedocument.wordprocessingml.document is not supported.
using DriveApp to get the Blob, rather than the Document Service:
Drive.Files.update(lpFile, lpFile.id, DriveApp.getFileById(smallPrintId).getBlob(), options);
This has the same issues as doc.getBlob(), and likely uses the same internal methods.
using DriveApp#getAs has the same errors as Document#getAs
Considering the limitation of the native Apps Script implementations, I then used the advanced service to obtain the Blob data. This is a bit trickier, since the File resource returned is not actually the file, but metadata about the file. Obtaining the Blob with the REST API requires exporting the file to a desired MimeType. We know from above that the PDF-formatted Blob fails to be properly imported, since that is the format used by the above attempts. We also know that the Google Docs format is not exportable, so the only one left is MS Word's .docx.
var blob = getBlobViaURL_(smallPrintId, MimeType.MICROSOFT_WORD);
Drive.Files.update(lpFile, lpFile.id, blob, options);
where getBlobViaURL_ implements the workaround from this SO question for the (still-broken) Drive.Files.export() Apps Script method.
This method successfully updates the existing "large print" file with the exact content from the "small print" file - at least for my test document. Given that it involves downloading content instead of using the internal, already-present data available to the export methods, it will likely fail for larger files.
Testing Script:
function copyContentFromAtoB() {
var smallPrintId = "some id";
var largePrintId = "some other id";
// You must first enable the Drive "Advanced Service" before this will work.
// Get the file metadata of the to-be-updated file.
var lpFile = Drive.Files.get(largePrintId);
// View available options on the relevant Drive REST API pages.
var options = {
updateViewedDate: false,
};
// Ideally this would use Drive.Files.export, but there is a bug in the Apps Script
// client library's implementation: https://issuetracker.google.com/issues/36765129
var blob = getBlobViaURL_(smallPrintId, MimeType.MICROSOFT_WORD);
// Replace the contents of the large print version with that of the small print version.
Drive.Files.update(lpFile, lpFile.id, blob, options);
}
// Below function derived from https://stackoverflow.com/a/42925916/9337071
function getBlobViaURL_(id, mimeType) {
var url = "https://www.googleapis.com/drive/v2/files/"+id+"/export?mimeType="+ mimeType;
var resp = UrlFetchApp.fetch(url, {
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken()}
});
return resp.getBlob();
}

Force download from S3 on click

I have files stored on S3, and I want to automatically download them for a user when they click a button
What I've done so far is to have a route
/lib/routes/download
var fs = Npm.require('fs');
Router.route("download", function() {
console.log('retrieving ' + this.params.signedURL);
this.response.writeHead(200, {'Content-type': 'appplication/pdf'}, this.params.signedURL);
this.response.end(fs.readFileSync(this.params.signedURL));
}, { where: 'server', path: '/d/:signedURL'});
But this doesn't work, because i Cant use fs on the client. And even if I could, im not sure this would work
Any advice on how best to accomplish this?
Easiest way to do this is to use the cfs:s3 package which is an add-on to CollectionFS. This not only supports S3 but also transparently breaks files up into smaller chunks during upload and download to/from S3.
I retrieve the signedUrl via a meteor method call, then do this when the user clicks a download button :
window.open(_signedURL,"_self");

Download a file with Tidesdk

How can I download a file and store it locally? I've searched the doc and google and couldn't find an example of it.
I tried this:
this.copyRemote = function(path,path2){
reader = Ti.Network.createHTTPClient();
writer = Ti.Filesystem.getFile(path2);
reader.open('GET',path);
reader.receive(writer);
}
But Tidesdk crashes while trying to download the file, the last messages on console are:
[12:42:39:647] [Ti.Network.HTTPClient] [Debug] Changing readyState from 0 to 1 for url:https://buttonpublish.com/api/images/7/image257189x142.jpg
[12:42:39:671] [Ti.Proxy] [Debug] Looking up proxy information for: https://buttonpublish.com/api/images/7/image257189x142.jpg
[12:
Seems like there has been success on the TideSDK Google Group using the code below:
var httpClient = Ti.Network.createHTTPClient();
httpClient.open('GET', path);
httpClient.receive(function(data) {
var file = Ti.Filesystem.getFile(path2);
var fileStream = file.open(Ti.Filesystem.MODE_APPEND);
fileStream.write(data);
fileStream.close();
});
Hope that helps, at least to point in the right direction.
I found that this works for my needs, which are just to get the file onto the machine:
function downloadFile( url ){
Ti.Platform.openApplication( url );
}
This opens the URL using the machine's default browser. One downside to this approach is that the user is normally prompted to confirm the download. I use the downloadFile function in case I want to change how this works in the future.

Resources