I am having this weird problem. I have an app that can create playlists with this code
var playlist = new Windows.Media.Playlists.Playlist();
...
WinJS.Utilities.id("appbar-save-button").listen("click", function ()
{
var savePicker = new Windows.Storage.Pickers.FolderPicker();
savePicker.fileTypeFilter.append("*");
savePicker.pickSingleFolderAsync().then(function (folder)
{
playlist.saveAsAsync(folder, "My Playlist", Windows.Storage.NameCollisionOption.replaceExisting, Windows.Media.Playlists.PlaylistFormat.windowsMedia);
});
})
The problem comes when I try to acces this file with this code
WinJS.Utilities.id("appbar-open-button").listen("click", function ()
{
var openPicker = Windows.Storage.Pickers.FileOpenPicker();
openPicker.fileTypeFilter.append(".wpl");
openPicker.pickSingleFileAsync().then(function (file)
{
Windows.Media.Playlists.Playlist.loadAsync(file).then(function (playlist)
{
// Print the name of the playlist.
});
});
})
On the commented line I get an exception : Cannot access the specified file or folder (⑰ᑲÕ). The item is not in a location that the application has access to (including application data folders, folders that are accessible via capabilities, and persisted items in the StorageApplicationPermissions lists). Verify that the file is not marked with system or hidden file attributes.
I have given the application Document library capabilities with File Type associations with type .wpl but still I get this exception. How can I fix it
EDIT: Adding the videos to the future acces list seems to solve the problem for app created playlists, but for random playlists the problem persists.
As far as i can see, the issue is not with the permission to load the 'playlist' file; using the file picker if a file is selected at any location on the computer, user will get access to the file; same applies to the folder picker where access to all files in the folder will be there. After that, if the selected file/folder is added to the FutureAccessList, the folder/file will be accessible later also.
The playlist may be containing files that are in the folders not accessible to user. To confirm this, try to open a playlist with no files or files in the music library location only - after giving the application 'music library' capability. If this works - application need to have settings to add folders with the music. playlist that will contain files in the selected folders will only load.
Related
I was looking for a solution so that people with access to a spreadsheet could upload files through it, researching I found some solutions, but as I will need these people to upload videos through the spreadsheet, some solutions that used Blob ended up being discarded.
Searching, I found this script made by Tanaike, apparently it solves practically all problems, I thought of pulling it into the spreadsheet using an html alert, thus allowing people to upload files with sizes greater than 50mb.
The script can be found here:
Resumable Upload For WebApps
The issue is that I'm having some problems getting it to work, basically I'm getting this error when trying to upload a file:
Error: <HTML> <HEAD> <TITLE>Not Implemented</TITLE> </HEAD> <BODY BGCOLOR="#FFFFFF" TEXT="#000000"> <H1>Not Implemented</H1> <H2>Error 501</H2> </BODY> </HTML>
Other than that, I have a few questions I'd like to clear up:
1- I'm not sure if with this script people with other accounts would be able to upload the files to my Google Drive, is it possible?
2- Is it possible implement it in a button on a spreadsheet and request that the file be uploaded in the same folder as that spreadsheet?
Sorry for the amount of questions, javascript and GAS are things that are not very present in my daily life, so I have a little difficulty.
Checking the developer console, the error returned from the server is accessNotConfigured. This happens when the GCP Project doesn't have the necessary APIs enabled. To fix this you need to create a new Cloud Project:
In the Google Cloud console, go to Menu > IAM & Admin > Create a Project.
In the Project Name field, enter a descriptive name for your project.
In the Location field, click Browse to display potential locations for your project. Then, click Select.
Click Create. The console navigates to the Dashboard page and your project is created within a few minutes.
After that you need to enable the Drive API:
In the Google Cloud console, go to Menu > More products > Google Workspace > Product Library.
Click the API that you want to turn on.
Click Enable.
Finally you need to attach the GCP project to your Apps Script Project:
Determine the Project number of your Cloud project.
Open the script whose Cloud project you want to replace.
At the left, click Project Settings.
Under Google Cloud Platform (GCP) Project, click Change project.
Enter the new project number and click Set project.
After attaching the standard project the error stopped showing up for me. The reason for this is that Google changed the way Apps Script creates GCP projects so now scripts may have Default or Standard projects. Default projects are essentially more restricted so you may have to create a Standard Project in certain scenarios. One these scenarios in the documentation is "To create a file-open dialog". Tanaike's code uses the same technique as the file-open dialogs to retrieve the access token from the server, which I believe is the cause of the error.
As for your other questions:
I'm not sure if with this script people with other accounts would be able to upload the files to my Google Drive, is it possible?
Only if you deploy it as a Web App, setting it to execute with your account and available to "Anyone with a Google account". This uses your account's access token to authorize so other users will upload to your account.
Is it possible implement it in a button on a spreadsheet and request that the file be uploaded in the same folder as that spreadsheet?
As I mentioned under 1., doing it within the spreadsheet probably won't work, but you can add the parents property to the request body on the HTML side to specify the folder. You can also retrieve it dynamically by calling google.script.run. Here's a sample I modified to do this:
google.script.run.withSuccessHandler(function(at) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
xhr.setRequestHeader('Authorization', "Bearer " + at.token);
xhr.setRequestHeader('Content-Type', "application/json");
xhr.send(JSON.stringify({
mimeType: fileType,
name: fileName,
parents: at.parent
}));
xhr.onload = function() {
doUpload({
location: xhr.getResponseHeader("location"),
chunks: chunks,
});
};
xhr.onerror = function() {
console.log(xhr.response);
};
}).getAt();
That's a part of the init() function in the index.html file. The at variable originally only received the access token retrieved from the server. I just modified it so it receives an object with both the access token and the folder ID, and I included the parent folder ID in the API call. You also need to modify the getAt() function in Code.gs to actually return the folder ID:
function getAt() {
var id = SpreadsheetApp.getActiveSpreadsheet().getId()
var folder = DriveApp.getFileById(id).getParents().next().getId()
return { token: ScriptApp.getOAuthToken(), parent: [folder] }
}
There's a lot to unpack here so I advise you to check the documentation. I think you'll have to go through the Web App route if you want other users to upload the files to your Drive.
Reference:
Web Apps
Communicate with Server Functions
Files.insert
Default and Standard Projects
I am trying to create a firebase function that downloads a photo off the web via URL and uploads it to firebase storage.
Using Axios to stream the file to the bucket. it appears the file gets uploaded but i cant download or view it.
This is my code:
let fileURL = 'https://www.example.file.path.png'
let myFile = await axios.get(fileURL, { responseType: 'stream' })
let destFile = bucket.file(photoId).createWriteStream({ contentType: myFile.headers['content-type']})
myFile.data.pipe(destFile)
And here is the storage console from firebase:
I have messed around with the storage api and attempted using the upload and save functions. using axios get and write streams is the closest that I'v got to getting this to work.
Reading the example in the docs only aids in my confusion because the file is never reference in the upload function.. just the file name??
Feel like i'm almost there considering the file or rather the name of the file is there and the size and the type.. just not the content?
This problem is related with Firebase console only. There is no problem with downloading with command: gsutil cp gs://<your bucket>/yourfile . (doc) and as well it is working in Google Cloud Console in Storage browser (direct link).
However indeed file uploaded like this is not possible to be downloaded or previewed with Firebase console.
After many tries I have realized that this is related with custom metadata Access token, which underneath is calledfirebaseStorageDownloadTokens. It appears automatically if ex. you download the file directly in Firebase console.
Anyway I noticed that value of the metadata is irrelevant. According to my test if you change your createWriteStream method parameters to:
let destFile = bucket.file(photoId)
.createWriteStream({
metadata: {
contentType: myFile.headers['content-type'],
metadata: {
firebaseStorageDownloadTokens: 'canBeAnyThing'
}
}
});
The problem disappears...
A file already downloaded to Firebase Storage and affected by the issue can be fixed by adding the same metadata. In the screenshot you have provided you can see "File Location" if you open you will see link "Create new access token" or as well you can add it in GCP Storage Browser adding it manually in "Edit metadata" for such object (remember to refresh FB console in browser).
At this point we can think of why it's looks like this. I have found interesting information in github here.
Is it possible to write a firebase cloud function that triggers when a new fila was created in firebase storage - onFinalize (but we don't know the exact bucket in advance) ?
Inside my firebase storage a have a folder 'loads' and inside I have folders named with load id like:
/loads/-Lw1UySdunYyFMrrV6tl
/loads/-LwisA5hkNl_uxw3k36f
/loads/-LwkPUm-q7wNv-wZ49Un
https://ibb.co/NnQkTyC here's a screenshot of storage
I want to trigger cloud function when new file has been created inside one of these folders. I don't know in andvance where the file will be created. I don't know if this is even possible. That's why I need an advice.
My main goal is to merge 2 pdf files in one within cloud functions. In my app (TMS written with vuejs) on frontend I create confirmationOrder.pdf using html2canvas/jsPDF and then save it to storage/loads/${loadID}. And later on user can manually upload POD.pdf on the same bucket. When it happens I want my cloud function to merge these two pdfs in one new file (in same storage bucket). But again I don't know the bucket in advance.
Here's how I upload PDFs in frontend:
async uploadConfPDF({ commit }, payload) {
const PDF = payload.PDF;
const loadID = payload.loadID;
const fileName = payload.fileName;
const fileData = await firebase
.storage()
.ref(`loads/${loadID}/${fileName}.pdf`)
.put(PDF);
const confOrderURL = await fileData.ref.getDownloadURL();
return confOrderURL;
},
Any help is highly appreciated. Sorry if my explanation could seem not clear enough. English is not my native language.
EDIT FOLLOWING YOUR QUESTION RE-WORKING
Based on your code and on the print screen of your Cloud Storage console, you are working in the default bucket of your project, which location's URL is gs://alex-logistics.appspot.com.
As we can see on the print screen of your Cloud Storage console, the files in your bucket are presented in a hierarchical structure, just like the file system on your local hard disk. However, this is just a way of presenting the files: there aren't genuine folders/directories in a bucket, the Cloud Storage console just uses the different part of the files paths to "simulate" a folder structure.
So, based on the above paragraphs, I think that your question can be re-phrased to "In a Cloud Function, how can I extract the different parts of the path of a file that is uploaded to the default bucket of my Firebase Project?".
Answer:
In a Cloud Function that is triggered when a file is added to the default bucket, you can get the file path as follows:
exports.yourCloudFunction = functions.storage.object().onFinalize(async (object) => {
const filePath = object.name; // File path in the bucket.
//...
});
Since we use an onFinalize event handler, you get the path of this new file by using the name property of the object Object, which is of type ObjectMetadata.
You can then use some String methods to, for example, extract from this path the ${loadID} you refer to in your question.
I have an ng-repeat that, among other thing, outputs on image:
<div class="installation" get-products install-index="{{$index}}" ng-repeat="installation in installations track by $index">
...
<img ng-src="{{installation.logo}}" />
...
</div>
When my app starts it downloads needed images and stores their location in a local database. When the page is viewed the installations are populated:
<div class="installation ng-scope" ng-repeat="installation in installations track by $index" install-index="43" get-products="">
...
<img src="C:/Users/.../AppData/Local/Packages/.../LocalState/installations/.../...png" ng-src="C:/Users/.../AppData/Local/Packages/.../LocalState/installations/.../...png">
...
</div>
(dots used to hide person and client data)
If I paste the src location into my browser I see the image so I know it's saved at that location. However, in my app it's not showing. This is a constant issue through the app with the downloaded files. I know the image are in the correct area and the src location is correct but none of them show.
--- EDIT ---
I do have white listing applied as I was getting an unsafe for file:///. Also, when I was using a relative path it was working fine. I had a preloaded database that pointed to file inside the app files.
I don't think it's an access issue since I have a .db file at the same location that all my data is being pulled from.
--- EDIT ---
I set it as file:///C:/... and I'm having the same issue.
I also tried file:///C:/... , http://localhost/..., http://localhost:/..., http://localhost:C/..., C:/..., and file:///.... None of witch give me anything. The first two localhost items do give me a broken image icon, that's about it. I'm not running a local server, just thought I'd try it.
You can do this in two different ways:
1) Use the file protocol
2) use a local host server to store the picture and access it from the local host
for security reasons you cannot use your file system path for images. you shouldn't even use it at all, because when your app gets hosted, you wouldn't be accessing the image via such paths.
method 1:
just add file:/// in place of the c:/. file is the protocol for your file system, just as http or HTTPS is a web protocol.
NB: I haven't tested or used this before so I'm not really certain. I'm posting this from a small mobile device. but I believe it should work.
method 2:
start your wampserver or python server or any local server you have. put the image in a folder where your server can access (if wampserver, this would be a folder or directory in your WWW). say the name of the folder is "my_images" and your wampserver is running on localhost.. you can access the image like so:
http://localhost/my_images/image_name
use this path for your ng-src.
Because I Cordova File and Windows weren't playing nice using the call for cordova.file.dataDirectory didn't work. Instead I used the fs object returned by window.requestFileSystem(...,function(fs){...});
When generating my save to path as well as the path to create directories and location data I used fs.winpath which returned C:/.... The web (which Cordova basically is) won't allow you to have access to local files not associated with the site/apps structure, which is now obvious.
I dug in to the fs object and found fs.root.nativeURL points to ms-appdata:///local/. Switching everything over to this still downloaded all files and directories to the same location but stored that to the database as the file location. When the app loaded the ms-appdata path instead of the C:/ path the images displayed.
oh, a Cordova app.. why don't you place the file in an images folder In your project. since all files will be loaded using index.html (I assume). you can easily refer to the file relative to the location of index.html. how I would normally organize my project is that, my index.html and folders containing resources like js, CSS etc would be on thesame level, so I can easily get the image files using ng-src="img/image_name". so I could have a structure like this
index.HTML
img
..image_name.ext
..image2.ext
css
..style.css test it in a browser location if it works, it will work on the device. Cordova would know how to translate d into something it can recognise.
This is some sample code, i quickly put together. I tested it and it worked. Firstly i create a directory using file plugin and then download to this directory using file transfer. Replace the url parameter of file transfer with the url you wish to download from.
$ionicPlatform.ready(function() {
$cordovaFile.createDir(cordova.file.externalDataDirectory,
file_location,false).then(
function(success){
return success;
},function(error){
return error;
}).then(function(value){
var url = material.file_uri;
var targetPath = cordova.file.externalDataDirectory
+ "/" +file_location + "/" + file_name;
var trustHosts = true
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
console.log(result)
}, function(err) {
console.log(err)
}, function (progress) {
$timeout(function () {
console.log(Math.floor((progress.loaded / progress.total) * 100));
})
});
})
})
I am making a browser based audio player. So for making a playlist from the local directory I am using :
<input type="file" id="getFile" />
Then I am using a button to confirm the playlist.On clicking the button I am calling a javascript function to change the src of the audio tag to play the new audio file selected in the playlist. I want the exact path of the file from the input file to run in the HTML5 audio player but it starts taking the path as C://Fakepath/filename.mp3. Can someone help me with this.
This is a security feature, by design. You should not be able to read the original file path of a file input into a browser form. File input is for reading file contents only, not metadata like path on the user's file system.
The good news is that you don't need the original file path. You can use FileReader's readAsDataURL to convert the file contents into a base64-encoded data URL and use that as the audio src. To read from #myUploadInput and output through #myAudioElement (also available as a working fiddle):
var reader = new FileReader();
reader.onload = function (event) {
document.getElementById("myAudioElement").src = event.target.result;
};
reader.readAsDataURL(document.getElementById("myUploadInput").files[0]);
if the user is 'building' / creating the playlist based on files they have locally you could do a 'browse' field (s) where they select the local audio files, then take the contents of the field (that Should include the paths to those images), build an array of the count/id, filename.mp3, and path... then, based on what is 'chosen' to play, just reassemble the full local path and play that file.
that would be an approach I would take anyway to see if it would work. the necessary piece here is getting the user to disclose the paths to the audio files... but Im still not 100% sure it would work given the security feature that the earlier commenter posted a link to.
if this were included in an application the user approved for local installation you could just refer to it using the 'application directory' and copy the file to that 'safe location' but since its web based it just really opens up a whole can of worms in terms of a potentially unapproved / authorized web function knowing your local directory structure. good luck, let me know if you find a solution.