How do I get an album's cover art in Xamarin.Android? - c#

Before anyone points it out, yes, I know there have been similar questions asked before. I've already tried solutions from them and they do not work, which is why I'm asking this question.
For reference, I'm using Android API 30.
So I'm performing a query on all audio files on the device using MediaStore. As of now I'm able to properly access artist/album/song IDs, names, etc. and use them elsewhere in my app. The one thing I'm unable to get though is the album art.
This is what my code looks like:
string[] columns = {
MediaStore.Audio.Media.InterfaceConsts.IsMusic,
MediaStore.Audio.Media.InterfaceConsts.Data,
MediaStore.Audio.Media.InterfaceConsts.Title,
MediaStore.Audio.Media.InterfaceConsts.CdTrackNumber,
MediaStore.Audio.Media.InterfaceConsts.Duration,
MediaStore.Audio.Media.InterfaceConsts.Id,
MediaStore.Audio.Media.InterfaceConsts.Album,
MediaStore.Audio.Media.InterfaceConsts.AlbumId,
MediaStore.Audio.Media.InterfaceConsts.Artist,
MediaStore.Audio.Media.InterfaceConsts.ArtistId,
};
ICursor? cursor = context.ContentResolver?.Query(MediaStore.Audio.Media.ExternalContentUri!, columns, null, null, null);
if (cursor is null)
{
return;
}
while (cursor.MoveToNext())
{
if (cursor.GetString(0) is not "1")
{
continue;
}
string trackPath = cursor.GetString(1)!;
string trackTitle = cursor.GetString(2)!;
int trackIndex = cursor.GetInt(3);
uint trackDuration = (uint)(cursor.GetFloat(4) / 1000);
long trackId = cursor.GetLong(5);
string albumTitle = cursor.GetString(6)!;
long albumId = cursor.GetLong(7);
string artistName = cursor.GetString(8)!;
long artistId = cursor.GetLong(9);
I initially tried the obvious method, which was adding MediaStore.Audio.Media.InterfaceConsts.AlbumArt to columns and getting the data from that column. But just adding that causes the application to freeze. Logging shows that adding it causes the method to freeze midway and not do anything. So this solution is out.
I then tried MediaMetadataRetriever, like this:
MediaMetadataRetriever retriever = new();
retriever.SetDataSource(trackPath);
byte[] artwork = retriever.GetEmbeddedPicture()!;
Bitmap albumArt = BitmapFactory.DecodeByteArray(artwork, 0, artwork.Length)!;
However, this also fails. I get an error message in the logs saying that MediaMetadataRetriever was unable to set the data source to that source.
So I figured maybe my data source was wrong. After doing some digging around I tried using a different path:
Uri contentUri = Uri.Parse("content://media/external/audio/albumart")!;
Uri albumArtUri = ContentUris.WithAppendedId(contentUri, albumId);
MediaMetadataRetriever retriever = new();
retriever.SetDataSource(albumArtUri.Path);
...
This also does not work. Neither does using MediaStore.Audio.Albums.ExternalContentUri.
I even tried opening a ParcelFileDescriptor from those URIs. Also doesn't work.
Does anyone know of a way that would definitely work? Most of the answers on StackOverflow seem to be quite dated, so they possibly don't apply to API 30 anymore. But I don't know what I'm doing wrong since the documentation isn't very detailed.

Related

LibreOffice Calc C# SDK: program to insert images into cells, stuck trying to create XGraphic

Background: I'm trying to write a program to insert an image into a cell of a spreadsheet. LibreOffice recently changed how this is done, and all the samples I could find use the old method which no longer works.
Technically I know that you can't "insert" an image into a cell and that such an image is an overlay on a DrawPage that sits on top of the spreadsheet to "decorate" it.
One of the first steps in doing this (the new way) is to create an XGraphic object which contains the image. The process is to create an XGraphicProvider and call it with MediaProperties that specify the image file URL to be loaded. I have a program that is supposed to do this but the resulting XGraphic is null. The LO SDK gives pretty much no information when you do something wrong; it just doesn't work.
Here is the code I have, with all the headers removed:
// addpic
// add picture to spreadsheet - debug version
class OpenOfficeApp {
[STAThread]
static void Main(string[] args) {
bool lreadonly;
string pqfile;
string pqURL;
string pqpic;
pqfile = "file:///D:/Documents/NSexeye/ODS%20File%20Access/"+
"addpix/addpic.ods";
pqpic = "addpic2";
pqURL = pqpic+".jpg";
lreadonly = false;
Console.WriteLine("Using: "+pqfile);
// get the desktop
XComponentContext XCC = uno.util.Bootstrap.bootstrap();
XMultiComponentFactory XMCF =
(XMultiComponentFactory)XCC.getServiceManager();
XMultiServiceFactory XMSF = (XMultiServiceFactory)XCC.getServiceManager();
XComponentLoader XCL =
(XComponentLoader)XMSF.createInstance("com.sun.star.frame.Desktop");
// open the spreadsheet
PropertyValue[] pPV = new PropertyValue[2];
pPV[0] = new PropertyValue();
pPV[0].Name = "Hidden";
pPV[0].Value = new uno.Any(true);
pPV[1] = new PropertyValue();
pPV[1].Name = "ReadOnly";
if (lreadonly) pPV[1].Value = new uno.Any(true);
else pPV[1].Value = new uno.Any(false);
XComponent XCo = XCL.loadComponentFromURL(pqfile,"_blank",0,pPV);
// create graphic object containing image
object oGP = XMCF.createInstanceWithContext(
"com.sun.star.graphic.GraphicProvider",XCC);
if (oGP == null) {
Console.WriteLine("oGP is null. Aborting.");
return;
}
XGraphicProvider XGP = (XGraphicProvider)oGP;
if (XGP == null) {
Console.WriteLine("XGP is null. Aborting.");
return;
}
pPV = new PropertyValue[1];
pPV[0] = new PropertyValue();
pPV[0].Name = "URL";
pPV[0].Value = new uno.Any(pqURL);
Console.WriteLine("Creating XGraphic containing "+pqURL);
XGraphic XG = XGP.queryGraphic(pPV);
// *** XG is null here
if (XG == null) {
Console.WriteLine("XG is null. Aborting.");
return;
}
// ... lots of stuff to be added here
// save and close the spreadsheet
XModifiable XM = (XModifiable)XCo;
XM.setModified(true);
XStorable XSt = (XStorable)XCo;
XSt.store();
XCloseable XCl = (XCloseable)XCo;
XCl.close(true);
// terminate LibreOffice
// *** I want this to not terminate it if something else is open
XDesktop XD = (XDesktop)XCL;
if (XD != null) XD.terminate();
}
}
I get a null for the XGraphic, in the place indicated in the comments. I don't know if the call to create it is failing, or if one of the earlier steps of the process are incorrect.
My goal here, in addition to getting my program working, is to create a sample program showing how to add an image to a Calc spreadsheet cell, and to manipulate such images. There are a fair number of people asking questions about this and none of the examples I've found will work. I think a good working sample will be of value.
I've spent a lot of time searching for information and code samples for this, with nothing that helps. I've tried to find ways to verify the validity of the XGraphicProvider interface with no luck. I've run out of things to try.
I'm hoping someone who knows about the LibreOffice SDK can take a look and maybe see what I'm doing wrong.
Update: I figured out what I was doing wrong: I was passing a bare filename in the "URL" property to XGraphicProvider. It has to be the same format (starting with "file:///") as the spreadsheet's file name specification.
Now I'm stuck with another property problem. The XGraphic has to be specified as a parameter to the GraphicObjectShape's Graphic property, but the setPropertyValue() function requires that it be a uno.Any type. I can't figure out how to specify an interface name like XGraphic as a uno.Any.
Here is the piece of code that won't compile, complaining that it can't convert an XGraphic to a uno.Any, in the first setPropertyValue call:
// set image XGraphic
XPropertySet XPS = (XPropertySet)XS;
XPS.setPropertyValue("Graphic",XG);
XPS.setPropertyValue("Name",new uno.Any(pqpic));
XG is an XGraphic type. Using "new uno.Any(XG)" doesn't work either, giving a similar compiler error.
After trying unsuccessfully for a few hours to get the latest LO SDK up and running, let me offer some untested ideas.
First of all, here is some working Basic code, no doubt similar to what you're translating from. The important line is oShape.Graphic = oProvider.queryGraphic(Props()).
oDoc = ThisComponent
oSheet = oDoc.CurrentController.ActiveSheet
pqURL = "file:///C:/Users/JimK/Desktop/addpic.jpg"
oProvider = createUnoService("com.sun.star.graphic.GraphicProvider")
oShape = oDoc.createInstance("com.sun.star.drawing.GraphicObjectShape")
Dim Props(0) as new com.sun.star.beans.PropertyValue
Props(0).Name= "URL"
Props(0).Value = pqURL
oShape.Graphic = oProvider.queryGraphic(Props())
oCell = oSheet.getCellByPosition(5,5)
oShape.Name = oCell.AbsoluteName + "##" + Props(0).Value
oShape.Anchor = oCell
oSheet.DrawPage.add(oShape)
'Resize
w = oShape.Graphic.Size.Width
h = oShape.Graphic.Size.Height
wcl = oCell.Size.Width
hcl = oCell.Size.Height
If w<>0 and h<>0 then
oCell.String=""
Dim Size as new com.sun.star.awt.Size
Size.Width = wcl
Size.Height = h*wcl/w
If Size.Height > hcl then
Size.Width = hcl*w/h
Size.Height = hcl
Endif
oShape.setSize(Size)
oShape.setPosition(oCell.Position)
erase oShape
Else
oShape.dispose()
Endif
Now, how to translate this to C#? It looks like you may need to explicitly specify the type. In the SDK example, there are calls like this.
xFieldProp.setPropertyValue(
"Orientation",
new uno.Any(
typeof (unoidl.com.sun.star.sheet.DataPilotFieldOrientation),
unoidl.com.sun.star.sheet.DataPilotFieldOrientation.DATA ) );
So in your case, something like this:
XPS.setPropertyValue(
"Graphic"
new uno.Any(
typeof(unoidl.com.sun.star.graphic.XGraphic),
XG));
Alternatively, follow the suggestion here: set GraphicURL, which should load the image and set Graphic for you.

Need a Way to Search through Event Logs by RecordID

I am trying to search through a folder with Event Logs in them, eventpath has the path of the specific Event Log I want to access. I want to use a specified RecordID to find it's correlated FormatDescription and display it in a MessageBox. I want to be able to use the eventpath to access each Event Log since I am using 6 separate .evtx files and need to use this method on all of them.
I found this solution, but I get an error when I'm trying to Query. I've tried to find a fix, but it seems as if it's just not going to work for what I need. I commented where exactly it is occurring in the code.
This is the exception: System.Diagnostics.Eventing.Reader.EventLogException: The specified path is invalid.
I can't find a fix for this code, but if anyone knows a fix or another way to approach searching through Event Logs by RecordID and giving the corresponding FormatDescription, it would be greatly appreciated.
I am using C# in Windows Presentation Foundation.
public void getDesc(string recordid)
{
string eventpath = getEventPath();
//takes off the .evtx of the path
string result = eventpath.Substring(0, eventpath.Length - 5);
//result1 is going to be similar to this:
//C:\Users\MyName\AppData\Local\Temp\randomTempDirectory\additional_files\DiagnosticInfo\WindowsEventLogs\Application
string sQuery = "*[System/EventRecordID=" + recordid + "]";
var elQuery = new EventLogQuery(result, PathType.LogName, sQuery);
//this is where it errors out
//error: Specified Channel Path is invalid
using (var elReader = new System.Diagnostics.Eventing.Reader.EventLogReader(elQuery))
{
List<EventRecord> eventList = new List<EventRecord>();
EventRecord eventInstance = elReader.ReadEvent();
try
{
while ((eventInstance = elReader.ReadEvent()) != null)
{
//Access event properties here:
string formatDescription = eventInstance.FormatDescription();
MessageBox.Show(formatDescription);
}
}
finally
{
if (eventInstance != null)
eventInstance.Dispose();
}
}
}

Cannot delete file from server folder

I'm working on a simple portfolio project. I would like to show images on a webpage that logged in users can edit. My problem is in the [HttpPost] Edit, more specifically this part:
if (ModelState.IsValid)
{
//updating current info
inDb = ModelFactory<ArtSCEn>.GetModel(db, artSCEn.ArtSCEnID);
inDb.LastModified = DateTime.Now;
inDb.TechUsed = artSCEn.TechUsed;
inDb.DateOfCreation = artSCEn.DateOfCreation;
inDb.Description = artSCEn.Description;
inDb.ArtSC.LastModified = DateTime.Now;
//validating img
if (Validator.ValidateImage(img))
{
inDb.ImageString = Image.JsonSerialzeImage(img);
}
else
{
//return to the UI becuase we NEED a valid pic
return View(artSCEn);
}
db.Entry(inDb).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
//[PROBLEMATIC PART STARTS HERE]
//updating the pic on the server
//getting the string info
string userArtImgFolder = Server.MapPath($"~/Content/Images/Artistic/{inDb.ArtSC.PersonID}");
string imgNameOnServer = Path.Combine(
userArtImgFolder,
$"{inDb.ArtSC.PersonID}_{inDb.ArtSC.ArtSCID}_{inDb.ArtSCEnID}{Path.GetExtension(img.FileName)}");
//deleting previous pic
System.IO.File.Delete(imgNameOnServer);
//creating a new pic
Image.ResizePropotionatelyAndSave(img, Path.Combine(
userArtImgFolder,
$"{inDb.ArtSC.PersonID}_{inDb.ArtSC.ArtSCID}_{inDb.ArtSCEnID}{Path.GetExtension(img.FileName)}"));
return RedirectToAction("Edit", "Art", new { id = inDb.ArtSCID });
}
When I get back the new picture and I want to delete the previous, System.IO.File.Delete() always triggers an exception that it cannot access the resource, because someone else is holding onto it. Any idea what that might be?
Maybe it's something simple, I'm new to ASP, but just can't figure it out.
UPDATE
Following on the suggestions in the comments section, I checked the processes with a tool called Process Monitor and it seems that indeed IIS is locking the resource:
This one appears 2 more times in the logs, by the way.
Judging by the fact that the operation is CreateFileMapping, I guess it has to do with either Server.MapPath() or Path.Combine(), however, the Server is an IDisposable (being derived from Controller), so can that be the one I should deal with?
Also, the resource I'm trying to delete is an image used on the website, which might be a problem, but that section of the website is not shown during this process.
I found the solution building on the comment of #Diablo.
The IIS was indeed holding on to the resource, but Server.MapPath() or any of that code had nothing to do with it: it was the Edit view my page returning the data to. With the help of this SO answer, it turns out I was careless with a BitMap that I used without a using statement in the view to get some image stats. I updated the helper function with the following code:
public static float GetImageWidthFromPath(string imgAbsolutPath, int offset)
{
float width = 0;
using (Bitmap b = new Bitmap(imgAbsolutPath))
{
width = b.Width - offset;
}
return width;
}
Now IIS does not hold on to the resource and I can delete the file.

tik4net hotspot user usage report in c#

what is the best way to get daily bytes-out and byte-in report for every user in hotspot list(without the user manager).i found the tik4net but i couldn't use it and i found almost no documentation on this reference.
i have tried the mk.cs and tik4net already but no luck so far.
this was the sample on using torch tool :
using (ITikConnection connection = ConnectionFactory.CreateConnection(TikConnectionType.Api))
{
connection.Open("IP", "USR", "PW");
var loadingContext = connection.LoadAsync<ToolTorch>(
torchItem => Console.WriteLine(torchItem.ToString()),
error => Console.WriteLine(error.ToString()),
connection.CreateParameter("interface", "DSL"),
connection.CreateParameter("port", "any"),
connection.CreateParameter("src-address", "0.0.0.0/0"),
connection.CreateParameter("dst-address", "0.0.0.0/0"));
Console.ReadLine();
loadingContext.Cancel();
{
so the question is:
what is the best reference in c# to get user reports without the user manager in c#?
can anyone please provide some sample code ?
UPDATE :
i just worked around and played with the code a little bit and got here :
using (ITikConnection connection = ConnectionFactory.CreateConnection(TikConnectionType.Api))
{
connection.Open("IP", "USR", "PW");
var hs = connection.LoadAll<HotspotActive>();
foreach (var user in hs)
{
var ids = user.Id;
listBox1.Items.Add(ids);
connection.Delete<HotspotActive>(user);
}
}
but i get an exception error on connection.Delete<HotspotActive>(user); , i dont know if i went the correct way.

How do you use the CopyIntoItems method of the SharePoint Copy web service?

I am attempting to load document files into a document library in SharePoint using the CopyIntoItems method of the SharePoint Copy web service.
The code below executes and returns 0 (success). Also, the CopyResult[] array returns 1 value with a "Success" result. However, I cannot find the document anywhere in the library.
I have two questions:
Can anyone see anything wrong with my code or suggest changes?
Can anyone suggest how I could debug this on the server side. I don't have a tremendous amount of experience with SharePoint. If I can track what is going on through logging or some other method on the server side it may help me figure out what is going on.
Code Sample:
string[] destinationUrls = { Uri.EscapeDataString("https://someaddress.com/Reports/Temp") };
SPCopyWebService.FieldInformation i1 = new SPCopyWebService.FieldInformation { DisplayName = "Name", InternalName = "Name", Type = SPListTransferSpike1.SPCopyWebService.FieldType.Text, Value = "Test1Name" };
SPCopyWebService.FieldInformation i2 = new SPCopyWebService.FieldInformation { DisplayName = "Title", InternalName = "Title", Type = SPListTransferSpike1.SPCopyWebService.FieldType.Text, Value = "Test1Title" };
SPCopyWebService.FieldInformation[] info = { i1, i2 };
SPCopyWebService.CopyResult[] result;
byte[] data = File.ReadAllBytes("C:\\SomePath\\Test1Data.txt");
uint ret = SPCopyNew.CopyIntoItems("", destinationUrls, info, data, out result);
Edit that got things working:
I got my code working by adding "http://null" to the SourceUrl field. Nat's answer below would probably work for that reason. Here is the line I changed to get it working.
// Change
uint ret = SPCopyNew.CopyIntoItems("http://null", destinationUrls, info, data, out result);
I think the issue may be in trying to set the "Name" property using the webservice. I have had some fail doing that.
Given the "Name" is the name of the document, you may have some success with
string targetDocName = "Test1Name.txt";
string destinationUrl = Uri.EscapeDataString("https://someaddress.com/Reports/Temp/" + targetDocName);
string[] destinationUrls = { destinationUrl };
SPCopyWebService.FieldInformation i1 = new SPCopyWebService.FieldInformation { DisplayName = "Title", InternalName = "Title", Type = SPListTransferSpike1.SPCopyWebService.FieldType.Text, Value = "Test1Title" };
SPCopyWebService.FieldInformation[] info = { i1};
SPCopyWebService.CopyResult[] result;
byte[] data = File.ReadAllBytes("C:\\SomePath\\Test1Data.txt");
uint ret = SPCopyNew.CopyIntoItems(destinationUrl, destinationUrls, info, data, out result);
Note: I have used the "target" as the "source" property. Don't quite know why, but it does the trick.
I didn't understand very well what you're tying to do, but if you're trying to upload a file from a local directory into a sharepoint library, i would suggest you create a webclient and use uploadata:
Example (VB.NET):
dim webclient as Webclient
webClient.UploadData("http://srvasddress/library/filenameexample.doc", "PUT", filebytes)
Then you just have to check in the file using the lists web service, something like:
listService.CheckInFile("http://srvasddress/library/filenameexample.doc", "description", "1")
Hope it was of some help.
EDIT: Don't forget to set credentials for the web client, etc.
EDIT 2: Update metada fields using this:
listService.UpdateListItems("Name of the Library, batchquery)
You can find info on building batch query's in here: link
The sourceurl is used in Sharepoint. It is a link back to the "Source Document." When in your document library, hover over the item, to the right appears a down pointing triangle. Clicking on it, brings up a menu. Click on the "View Properties" Option. On this page you will see the following "This item is a copy of http://null ( Go To Source Item | Unlink )"
Because we are using the Copy function Sharepoint is keeping track of the "Source item" as part of the Document Management feature.

Categories

Resources