Storing objects in IsolatedStorageSettings - c#

I have an object I want to store in the IsolatedStorageSettings, which I wan't to reuse when the application restarts.
My problem lies in that the code I have written for some reason does not remember the object when trying to access the key upon restarting it.
namespace MyNameSpace
{
public class WindowsPhoneSettings
{
private const string SelectedSiteKey = "SelectedSite";
private IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
private T RetrieveSetting<T>(string settingKey)
{
object settingValue;
if (isolatedStore.TryGetValue(settingKey, out settingValue))
{
return (T)settingValue;
}
return default(T);
}
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
if (isolatedStore.Contains(Key))
{
if (isolatedStore[Key] != value)
{
isolatedStore[Key] = value;
valueChanged = true;
}
}
else
{
isolatedStore.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
public MobileSiteDataModel SelectedSite
{
get
{
return RetrieveSetting<MobileSiteDataModel>(SelectedSiteKey);
}
set
{
AddOrUpdateValue(SelectedSiteKey, value);
isolatedStore.Save();
}
}
}
}
I then instantiate WindowsPhoneSettings in App.xaml.cs and make a public getter and setter for it. To be able to access it in the whole application. Debugging this shows that the right object gets stored in the isolated store, but when closing the app and reopening it isolated store seems to be empty. I have tried this on both the emulator and a real device. As you can see I do call the save method when setting the object.
What am I doing wrong here?

I ended up saving the settings to a file in the isolated storage as IsolatedStorageSettings never seemed to work.
So my code ended up like this:
public class PhoneSettings
{
private const string SettingsDir = "settingsDir";
private const string SettingsFile = "settings.xml";
public void SetSettings(Settings settings)
{
SaveSettingToFile<Settings>(SettingsDir, SettingsFile, settings);
}
public Settings GetSettings()
{
return RetrieveSettingFromFile<Settings>(SettingsDir, SettingsFile);
}
private T RetrieveSettingFromFile<T>(string dir, string file) where T : class
{
IsolatedStorageFile isolatedFileStore = IsolatedStorageFile.GetUserStoreForApplication();
if (isolatedFileStore.DirectoryExists(dir))
{
try
{
using (var stream = new IsolatedStorageFileStream(System.IO.Path.Combine(dir, file), FileMode.Open, isolatedFileStore))
{
return (T)SerializationHelper.DeserializeData<T>(stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Could not retrieve file " + dir + "\\" + file + ". With Exception: " + ex.Message);
}
}
return null;
}
private void SaveSettingToFile<T>(string dir, string file, T data)
{
IsolatedStorageFile isolatedFileStore = IsolatedStorageFile.GetUserStoreForApplication();
if (!isolatedFileStore.DirectoryExists(dir))
isolatedFileStore.CreateDirectory(dir);
try
{
string fn = System.IO.Path.Combine(dir, file);
if (isolatedFileStore.FileExists(fn)) isolatedFileStore.DeleteFile(fn); //mostly harmless, used because isolatedFileStore is stupid :D
using (var stream = new IsolatedStorageFileStream(fn, FileMode.CreateNew, FileAccess.ReadWrite, isolatedFileStore))
{
SerializationHelper.SerializeData<T>(data, stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Could not save file " + dir + "\\" + file + ". With Exception: " + ex.Message);
}
}
}
And a settings class just containing the stuff I want to save. This could be:
class Settings
{
private string name;
private int id;
public string Name
{
get { return name; }
set { name = value; }
}
public int Id
{
get { return id; }
set { id = value; }
}
}
EDIT: Sample of how SerializationHelper could be implemented
public static class SerializationHelper
{
public static void SerializeData<T>(this T obj, Stream streamObject)
{
if (obj == null || streamObject == null)
return;
var ser = new DataContractJsonSerializer(typeof(T));
ser.WriteObject(streamObject, obj);
}
public static T DeserializeData<T>(Stream streamObject)
{
if (streamObject == null)
return default(T);
var ser = new DataContractJsonSerializer(typeof(T));
return (T)ser.ReadObject(streamObject);
}
}

Objects stored in IsolatedStorageSettings are serialised using the DataContractSerializer and so must be serializable. Ensure they can be or serialize (and deserialize) them yourself before adding to (and after removing from) ISS.
If the items aren't there when trying to retrieve then it may be that they couldn't be added in the first place (due to a serialization issue).

Here is the code I use to save an object to isolated storage and to load an object from isolated storage -
private void saveToIsolatedStorage(string keyname, object value)
{
IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
isolatedStore.Remove(keyname);
isolatedStore.Add(keyname, value);
isolatedStore.Save();
}
private bool loadObject(string keyname, out object result)
{
IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
result = null;
try
{
result = isolatedStore[keyname];
}
catch
{
return false;
}
return true;
}
Here is code I use to call the above -
private void SaveToIsolatedStorage()
{
saveToIsolatedStorage("GameData", GameData);
}
private void LoadFromIsolatedStorage()
{
Object temp;
if (loadObject("GameData", out temp))
{
GameData = (CGameData)temp;
}
else
{
GameData.Reset();
}
}
Note that the objects I save and restore like this are small and serializable. If my object contains a 2 dimensional array or some other object which is not serializable then I perform my own serialization and deserialization before using iso storage.

What if you changed RetrieveSetting<T> to this:
private T RetrieveSetting<T>(string settingKey)
{
T settingValue;
if(isolatedStore.TryGetValue(settingKey, out settingValue))
{
return (T)settingValue;
}
return default(T);
}
Notice that the object being fetched is being declared as type T instead of object.

Related

Unity3D Save or Load each Level and their own variables

I am new to stackoverflow and to Unity3D, so I am sorry if I am doing things wrong.
So currently, I am making a puzzle game. It has 50 different levels.
I need for each of them, to save 3 or 4 variables.
For example, when level 1 is cleared, I want it to store (int)hitCounts, (bool)cleared, (int)bestHitCounts.
I don't wanna use playerPrefs, as I don't want it to be readable from outside the box. I want it be converted to a binary file.
here is what I have :
#1 : made a static class TGameDat
[System.Serializable]
public class TGameDat
{
public int tGameDatInt;
public bool tGameDatBool;
public int tSceneIndex;
public TGameDat (TPlayer player)
{
tGameDatInt = player.tInt;
tGameDatBool = player.tBool;
tSceneIndex = player.tScene;
}
}
#2 : then made Tplayer(monobehaviour)
public class TPlayer : MonoBehaviour
{
public int tInt = 0;
public bool tBool = false;
public int tScene;
public List<TPlayer> TestGameDatList = new List<TPlayer>();
private void Start()
{
TSceneMaker();
}
public void TSceneMaker()
{
tScene = SceneManager.GetActiveScene().buildIndex;
}
public void TNextScene()
{
SceneManager.LoadScene(tScene + 1);
}
public void TPreviousScene()
{
SceneManager.LoadScene(tScene - 1);
}
public void TSaveVariables()
{
TSave.TSavePlayer(this);
TestGameDatList.Add(this);
Debug.Log("saved");
Debug.Log(tInt + " " + tBool + " " + tScene);
}
public void TLoadVariables()
{
List<TGameDat> data = TSave.TLoadPlayer(this);
Debug.Log("loaded. data count = " + data.Count + " tSceneIndex " + tScene);
tInt = data[0].tGameDatInt;
tBool = data[0].tGameDatBool;
tScene = data[0].tSceneIndex;
}
}
#3 : finally I created a save and load system :
public static class TSave
{
public static void TSavePlayer (TPlayer player)
{
BinaryFormatter formatter = new BinaryFormatter();
List<TGameDat> data = new List<TGameDat>();
string path = Application.persistentDataPath + "/Tsave_" + player.tScene + ".fun";
if(File.Exists(path))
{
FileStream stream = File.Open(path, FileMode.Open);
data.Add(new TGameDat(player));
formatter.Serialize(stream, data);
stream.Close();
}
else
{
FileStream stream = File.Create(path);
data.Add(new TGameDat(player));
formatter.Serialize(stream, data);
stream.Close();
}
}
public static List<TGameDat> TLoadPlayer(TPlayer player)
{
string path = Application.persistentDataPath + "/Tsave_" + player.tScene + ".fun";
if(File.Exists(path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = File.Open(path, FileMode.Open);
List<TGameDat> data = new List<TGameDat>();
data = formatter.Deserialize(stream) as List<TGameDat>;
stream.Close();
return data;
}
else
{
Debug.LogError("Save file not found in " + path);
return null;
}
}
}
So, here are my problems :
1 : in the current situation, each scene compiles a binary file. So at the end, it will have a bunch of binary files piled up... Like 50, as I have 50 scenes... isn't it too many?
2 : of course I tried the make a single save file using List, and each level would come to add its own variable data in it.
But instead of adding the data, it would simply replace the previous data. Then there is always only 1 index in the List.
Therefore, when I load, the variables are from the last played level! And when I try to play another level after playing the first level, because there is only 1 index in the list, I get out of range error.
How shall I approach this?
sorry for the long long text!
thank you for your inputs!
first thing first, do you really need every level to have its own save data? Because if you only need to store the data between one level and another I would suggest you use some kind of PlayerState class that stores the data of the previous level.
But if you really need to store the data of every level then I'll recommend you using a dictionary rather than a simple list.
Here is an example of how I would do it
Note: I haven't tested this code yet!
SaveGameManager class
public string SavePath => Application.persistentDataPath + "/save.dat";
public static SaveGameManager Instance; // Singleton pattern
private Dictionary<string, TGameDat> gameData;
private void Awake()
{
if (Instance != null)
{
Destroy(this.gameObject);
return;
}
// Singleton initialization
Instance = this;
// Keep the object when changing scenes
DontDestroyOnLoad(this.gameObject);
LoadGameData();
}
public TGameDat GetGameData(string key)
{
if (gameData.TryGetValue(key, out TGameDat data))
{
return data;
}
Debug.Log($"Unable to find saved data with key {key}");
return null;
}
public void SetGameData(string key, TGameDat data)
{
// Sets a value with given key and save it to file
gameData[key] = data;
SaveGameData();
}
public void SaveGameData()
{
Serializer.SaveBinaryFile(gameData, SavePath);
}
public void LoadGameData()
{
var savedData = Serializer.LoadBinaryFile(SavePath);
if (savedData != null)
{
gameData = (Dictionary<string, TGameDat>)savedData;
}
else
{
// Creating and saving new data because we can't found
// any that already stored in path
gameData = new Dictionary<string, TGameDat>();
SaveGameData();
}
}
And then, the Serializer class
public static void SaveBinaryFile(object data, string path)
{
using (var stream = new FileStream(path, FileMode.Create))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, data);
}
}
public static object LoadBinaryFile(string path)
{
if (!File.Exists(path))
{
// Trying to load a file that does not exist
return null;
}
using (var stream = new FileStream(path, FileMode.Open))
{
var formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
}
And then you can use it like this
public TGameDat data;
public void TSaveVariables()
{
SaveGameManager.Instance.SetGameData(level.id, this.data);
}
public void TLoadVariables()
{
var savedData = SaveGameManager.Instance.GetGameData(level.id);
if (savedData != null)
{
this.data = savedData;
}
else
{
// We don't have any save file for this level yet
savedData = new TGameDat();
}
}
You can change level.id to whatever identifier you wanted to use.

Serialize and Deserialize list of object, without break encapsulation

I have a class called Member that I want to save and load in a XML file.
Here is my methods to load/save
public T LoadGenericDataType<T>(string filename)
{
XmlSerializer xms = new XmlSerializer(typeof(T));
FileStream fileStream = new FileStream(this._rootFolder + filename, FileMode.Open, FileAccess.ReadWrite);
try
{
Object v = xms.Deserialize(fileStream);
fileStream.Close();
return (T) v;
}
catch (Exception e)
{
fileStream.Close();
throw e;
}
}
public bool SaveGenericDataType<T>(T data, string filename)
{
XmlSerializer xms = new XmlSerializer(typeof(T));
FileStream fileStream = new FileStream(this._rootFolder + filename, FileMode.Create, FileAccess.Write);
try
{
xms.Serialize(fileStream, data);
fileStream.Close();
return true;
}
catch (Exception e)
{
fileStream.Close();
return false;
}
}
In my member class I save a property called Boats, and I don't want to send the original List to any other class so I do a copy of it.
public List<Boat> Boats
{
get => _boats; // this will break encapsulation, but will make it easier to serialize( bad design my me :/ )
set => _boats = value;
}
public List<Boat> Boats1
{
get
{
List<Boat> copyOfBoats = new List<Boat>(); // this will cause LOADING to fail not saving.
foreach (Boat boat in _boats)
{
copyOfBoats.Add(boat);
}
return copyOfBoats;
}
set => _boats = value;
}
What am I missing? If I try to load an xml with the "Boats1" Property it will fail.
Okay I managed to fixed the problem by this.
public List<Boat> Boats
{
get
{
if (_boats.Count == 0)
return _boats;
List<Boat> copyOfBoats = new List<Boat>(); .
foreach (Boat boat in _boats)
{
copyOfBoats.Add(boat);
}
return copyOfBoats;
}
set => _boats = value;
}
But it will still break encapsulation if the member don't have any boats.
Maybe try
public List<Boat> Boats1
{
get
{
List<Boat> copyOfBoats = new List<Boat>();
if (_boats.Count > 0)
{
foreach (Boat boat in _boats)
{
copyOfBoats.Add(boat);
}
}
return copyOfBoats;
}
set => _boats = value;
}
That should keep it from returning the orginal list of boats.

Custom object is serializable but not deserializable

I get an object of a class with some properties by calling its own static function for an instance. If there is a XML file the object tries to load it and add its values to the instance itself. Then it will save the XML again in case there are missing options in the XML file.
I created a small console app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;
using System.Xml;
namespace Test
{
public class Program
{
static void Main(string[] args)
{
TaskServerSettings s = TaskServerSettings.LoadNew();
}
}
public class TaskServerSettings : IEqualityComparer
{
#region SETTINGS PROPERTIES
public bool Enabled { get; set; }
public int CheckInterval { get; set; }
#endregion
#region CONSTRUCTORS AND METHODS
public TaskServerSettings()
{
this.init();
}
public TaskServerSettings(string settingsFile)
{
this.init();
if (settingsFile != null)
{
if (File.Exists(settingsFile))
{
this.Load(settingsFile);
}
this.Save(settingsFile);
}
}
private void init()
{
this.Enabled = true;
this.CheckInterval = 5000;
}
public void Absorb(TaskServerSettings newSettings)
{
this.Enabled = newSettings.Enabled;
this.CheckInterval = newSettings.CheckInterval;
}
public static TaskServerSettings LoadNew(string settingsFile = null)
{
if (settingsFile == null)
{
settingsFile = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.TrimEnd('\\')) + #"\TaskServerSettings.xml";
}
return new TaskServerSettings(settingsFile);
}
public bool Load(string settingsFile = null)
{
if (settingsFile == null)
{
settingsFile = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.TrimEnd('\\')) + #"\TaskServerSettings.xml";
}
if (!File.Exists(settingsFile))
{
throw new FileNotFoundException("Could not find \"" + settingsFile + "\" to load settings.");
}
bool result = false;
using (FileStream fs = new FileStream(settingsFile, FileMode.Open))
{
XmlSerializer xs = new XmlSerializer(this.GetType());
if (!xs.CanDeserialize(XmlReader.Create(fs)))
{
throw new XmlException("\"" + settingsFile + "\" does not have a valid TaskServerSettings XML structure.");
}
//try
//{ // +- InvalidOperationException - Error in XML document (0,0).
// v The root element is missing.
this.Absorb(xs.Deserialize(fs) as TaskServerSettings);
result = true;
//}
//catch { }
}
return result;
}
public bool Save(string settingsFile = null)
{
if (settingsFile == null)
{
settingsFile = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.TrimEnd('\\')) + #"\TaskServerSettings.xml";
}
bool result = false;
using (FileStream fs = new FileStream(settingsFile, FileMode.Create))
{
XmlSerializer xs = new XmlSerializer(this.GetType());
try
{
xs.Serialize(fs, this);
result = true;
}
catch { }
}
return result;
}
#endregion
public bool Equals(TaskServerSettings settingsToCompare)
{
if (this.Enabled != settingsToCompare.Enabled ||
this.CheckInterval != settingsToCompare.CheckInterval)
{
return false;
}
return true;
}
bool IEqualityComparer.Equals(object x, object y)
{
return x.Equals(y);
}
int IEqualityComparer.GetHashCode(object obj)
{
throw new NotSupportedException();
}
}
}
Writing the object with its default property values in the first run works pretty good.
The XML file looks like this then:
<?xml version="1.0"?>
<TaskServerSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Enabled>true</Enabled>
<CheckInterval>5000</CheckInterval>
</TaskServerSettings>
However, deserializing the same file on the second run causes the error when it tries to load the file on
xs.Deserialize(fs) as TaskServerSettings.
InvalidOperationException - Error in XML document (0,0).
The root element is missing.
I already tried to avoid the static method and tried new as well as I already tried to remove the IEqualityComparer parent + the last three methods. Without success.
I wonder, whats the cause of this error?
When you execute this statement:
if (!xs.CanDeserialize(XmlReader.Create(fs)))
it starts reading the stream. So when you call Deserialize later, the stream is not at the start, so the deserialization fails. You need to rewind the stream by setting fs.Position = 0

C# XmlSerialisation addin serialisation

I have written an Interface for writing a very very simple Plugin. In fact it is just a class that is loaded at runtime out of a dll file and is stored as Property in another class. That class that stores the interface has to get serialized. As example this is my serialized object:
<?xml version="1.0" encoding="utf-8"?><MD5HashMapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.namespace.net" />
But now If i want to load that Object I get an Exception:
As example :
{"<MD5HashMapper xmlns='http://www.vrz.net/Vrz.Map'> was not expected."}
So does anyone has an idea how to solve that problem?
Code:
I have an Interface named IMap that is shared in a dll file to create Addins based on that interface:
public interface IMap
{
object Map(object input);
}
I also have different Mappers (you can pass an input through them and they modify the output). All Mappers are derived from:
[XmlInclude(typeof(ConstMapper))]
[XmlInclude(typeof(FuncMapper))]
[XmlInclude(typeof(IdentMapper))]
[XmlInclude(typeof(NullMapper))]
[XmlInclude(typeof(RefMapper))]
[XmlInclude(typeof(VarMapper))]
[XmlInclude(typeof(TableMapper))]
[XmlInclude(typeof(AddinMapper))]
public class MapperBase:ComponentBase,IMap
{ public virtual object Map(object input) {
throw new NotImplementedException("Diese Methode muss überschrieben werden");
}
public override string ToString() {
return ShortDisplayName;
}
}
Just forget ComponentBase. It is not important for this...
Now i also have a AddinMapper. The main function of that mapper is to cast create MapperBase Object out of the IMap object:
And that is exactly that class I want to seralize including the properties of the Mapper Property (type IMap).
public class AddinMapper : MapperBase
{
private static MapperBase[] _mappers;
const string addinDirectory = #"Addin\Mappers\";
//Mappers from *.dll files are loaded here:
[XmlIgnore]
public static MapperBase[] Mappers
{
get
{
if (_mappers == null)
{
List<MapperBase> maps = new List<MapperBase>();
foreach (string dll in Directory.GetFiles(addinDirectory, "*.dll"))
{
if (Path.GetFileName(dll) != "IMap.dll")
{
var absolutePath = Path.Combine(Environment.CurrentDirectory, dll);
Assembly asm = Assembly.LoadFile(absolutePath);
foreach (Type type in asm.GetTypes().ToList().Where(p => p.GetInterface("IMap") != null))
{
maps.Add(new AddinMapper((IMap)Activator.CreateInstance(type)));
}
}
}
Mappers = maps.ToArray();
}
return _mappers;
}
set
{
_mappers = value;
}
}
IMap _base;
public string MapperString { get; set; }
[XmlIgnore()]
public IMap Mapper
{
get
{
if (_base == null)
{
Type type = null;
foreach (MapperBase mapperBase in Mappers)
{
if (mapperBase is AddinMapper && ((AddinMapper)mapperBase).Mapper.GetType().FullName == _mapperName)
{
type = (mapperBase as AddinMapper).Mapper.GetType();
break;
}
}
if (type != null)
{
XmlSerializer serializer = new XmlSerializer(type);
using (StringReader reader = new StringReader(MapperString))
{
Mapper = (IMap)serializer.Deserialize(reader);
}
}
}
return _base;
}
private set
{
_base = value;
StoreMapperString();
}
}
string _mapperName;
[System.ComponentModel.Browsable(false)]
public string MapperName
{
get
{
return _mapperName;
}
set
{
_mapperName = value;
}
}
public AddinMapper(IMap baseInterface) : this()
{
Mapper = baseInterface;
_mapperName = baseInterface.GetType().FullName;
}
public AddinMapper()
{
}
public override object Map(object input)
{
return Mapper.Map(input);
}
public override string ToString()
{
return Mapper.ToString();
}
private void StoreMapperString()
{
MemoryStream memstream = new MemoryStream();
XmlStore.SaveObject(memstream, Mapper);
using (StreamReader reader = new StreamReader(memstream))
{
memstream.Position = 0;
MapperString = reader.ReadToEnd();
}
}
}
An example for such a addin would be:
public class ReplaceMapper : IMap
{
public string StringToReplace { get; set; }
public string StringToInsert { get; set; }
public object Map(object input)
{
if (input is string)
{
input = (input as string).Replace(StringToReplace, StringToInsert);
}
return input;
}
}
And the Problem is I want to save the Settings like StringToReplace,... as xml
I ve solved my problem:
I really don t know why but take a look at this article: http://www.calvinirwin.net/2011/02/10/xmlserialization-deserialize-causes-xmlns-was-not-expected/
(if link is dead later)
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = elementName;
xRoot.IsNullable = true;
XmlSerializer ser = new XmlSerializer(typeof(MyObject), xRoot);
XmlReader xRdr = XmlReader.Create(new StringReader(xmlData));
MyObject tvd = (MyObject)ser.Deserialize(xRdr);
Now the important thing: It does not matter if you don t get an excption on serialization. You have to add the XmlRootAttribute on both ways: Serialisation and Deserialization.

itunes listening to

within windows live messenger, it is possible to share the song you are currently listening to. what would i need to do to get this working within c# like libarys etc cannot find the correct documentation on google.
You'll need to use the iTunes SDK to interact with iTunes from .NET. So there's your Google search term. :)
Here's a start:
http://blogs.msdn.com/b/noahc/archive/2006/07/06/automating-itunes-with-c-in-net.aspx
http://blogs.msdn.com/b/dancre/archive/2004/05/08/128645.aspx
Here is a script for LinqPad in C# which does as requested. (see LinqPad.com)
Bonus! Artwork view.
It looks like this:
<Query Kind="Program">
<Namespace>iTunesLib</Namespace>
<Namespace>System.Security.Cryptography</Namespace>
</Query>
void Main()
{
var track = new iTunesApp().CurrentTrack;
if (track == null)
"nothing playing".Dump();
else
new Viewer(track,true).Dump();
}
public class Viewer
{
const string PREFIX = "itlps-";
private IITFileOrCDTrack store;
private bool materialize;
public string album { get { return store.Album; } }
public string band { get { return store.Artist; } }
public string song { get { return store.Name; } }
public string desc { get { return store.Description; } }
public int? artCnt { get {
if (store.Artwork == null) return null;
else return store.Artwork.Count; }
}
public IEnumerable<ImageViewer> art { get {
if (materialize)
{
foreach(var artT in store.Artwork)
{
var art = artT as IITArtwork;
string ext = ".tmp";
switch(art.Format)
{
case ITArtworkFormat.ITArtworkFormatBMP:
ext = ".BMP";
break;
case ITArtworkFormat.ITArtworkFormatJPEG:
ext = ".JPG";
break;
case ITArtworkFormat.ITArtworkFormatPNG:
ext = ".PNG";
break;
}
string path = Path.Combine(Path.GetTempPath(),PREFIX+Path.GetRandomFileName()+ext);
art.SaveArtworkToFile(path);
yield return new ImageViewer(path);
}
}
yield break; }
}
public Viewer(IITFileOrCDTrack t,bool materializeArt = false)
{
store = t;
materialize = materializeArt;
}
public Viewer(IITTrack t,bool materializeArt = false)
{
store = t as IITFileOrCDTrack;
materialize = materializeArt;
}
}
public class ImageViewer
{
public string hash { get { return _hash.Value; } }
static private string _path { get; set; }
public object image { get { return _image.Value; } }
static private SHA1Managed sha = new SHA1Managed();
private Lazy<object> _image = new Lazy<object>(() => {return Util.Image(_path);});
private Lazy<string> _hash = new Lazy<string>(() =>
{
string hash = string.Empty;
using (FileStream stream = File.OpenRead(_path))
{
byte [] checksum = sha.ComputeHash(stream);
hash = BitConverter.ToString(checksum).Replace("-", string.Empty);
}
return hash;
});
public ImageViewer(string path)
{
_path = path;
}
}
last i checked this functionality is included out of the box all you need is to have itunes and windows live messenger installed and activate "what im listening to" and it shows this in your messenger status. if you are looking to create a bot that messages this out to a contact that is a different story tho that you will need to write a script for

Categories