convert library explorer to win forms

This commit is contained in:
Luke Pulverenti 2014-02-15 12:17:09 -05:00
parent 8b71ab2e7d
commit 60213b2d3c
7 changed files with 2853 additions and 842 deletions

View file

@ -1,178 +0,0 @@
<Window x:Class="MediaBrowser.ServerApplication.LibraryExplorer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MediaBrowser.ServerApplication"
Title="Library Explorer"
Height="733.75"
Width="893">
<Grid Margin="0,0,0,10">
<TreeView x:Name="tvwLibrary"
HorizontalAlignment="Left"
Margin="10,54,0,0"
Width="399"
SelectedItemChanged="tvwLibrary_SelectedItemChanged"
Height="417"
VerticalAlignment="Top">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Name="img"
Width="20"
Height="20"
Stretch="Fill"
Source="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type TreeViewItem}},
Path=Tag,
Converter={x:Static local:ItemToImageConverter.Instance}}" />
<TextBlock Text="{Binding}"
Margin="5,0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
<Button x:Name="btnLoad"
Content="Load"
HorizontalAlignment="Left"
Margin="218,25,0,0"
VerticalAlignment="Top"
Width="75"
RenderTransformOrigin="0.373,0.045"
Click="btnLoad_Click"
Visibility="Hidden" />
<TextBox x:Name="txtData"
Margin="427,54,0,0"
HorizontalAlignment="Left"
TextWrapping="Wrap"
VerticalAlignment="Top"
Height="417"
Width="444"
VerticalScrollBarVisibility="Auto" />
<Label Content="Contents&#xD;&#xA;"
HorizontalAlignment="Left"
Margin="440,23,0,0"
VerticalAlignment="Top"
Height="26"
Width="74"
FontWeight="Bold" />
<ListView x:Name="lstPreviews"
HorizontalAlignment="Left"
Margin="10,476,0,10"
Width="861">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"
MinWidth="100" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Image Source="{Binding Preview}"
Height="140"
MaxWidth="300"
Grid.Row="0" />
<TextBlock Text="{Binding Name}"
Grid.Row="1"
FontFamily="Segoe Media Center"
FontSize="14"
FontWeight="Bold"
HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ComboBox x:Name="ddlProfile"
HorizontalAlignment="Left"
Margin="10,25,0,0"
VerticalAlignment="Top"
Width="191"
SelectionChanged="ddlProfile_SelectionChanged" />
<Label Content="View;"
HorizontalAlignment="Left"
Margin="10,1,0,0"
VerticalAlignment="Top"
Height="24"
Width="119"
FontWeight="Bold" />
<Label x:Name="lblLoading"
Content="Loading..."
HorizontalAlignment="Left"
Margin="140,150,0,0"
VerticalAlignment="Top"
FontSize="18"
Foreground="LightGray"
Visibility="Hidden"
FontStyle="Italic"
FontWeight="Bold"
RenderTransformOrigin="0.258,0.5" />
<Label x:Name="lblObjType"
Content="Type:&#xA;"
HorizontalAlignment="Left"
Margin="534,23,0,0"
VerticalAlignment="Top"
Height="26"
Width="158"
FontWeight="Bold" />
<Button x:Name="btnRefresh"
Content="Refresh"
HorizontalAlignment="Left"
Margin="712,25,0,0"
VerticalAlignment="Top"
Width="82"
Click="btnRefresh_Click" />
<CheckBox x:Name="cbxForce"
Content="Force"
HorizontalAlignment="Left"
Margin="816,28,0,0"
VerticalAlignment="Top"
RenderTransformOrigin="-0.14,-0.562"
Width="51" />
<ComboBox x:Name="ddlIndexBy"
HorizontalAlignment="Left"
Margin="218,25,0,0"
VerticalAlignment="Top"
Width="92"
SelectionChanged="ddlIndexBy_SelectionChanged" />
<Label x:Name="lblIndexBy"
Content="Index By"
HorizontalAlignment="Left"
Margin="218,0,0,0"
VerticalAlignment="Top"
Height="34"
Width="75"
FontWeight="Bold" />
<ComboBox x:Name="ddlSortBy"
HorizontalAlignment="Left"
Margin="315,25,0,0"
VerticalAlignment="Top"
Width="94"
SelectionChanged="ddlSortBy_SelectionChanged" />
<Label x:Name="lblSortBy"
Content="Sort By"
HorizontalAlignment="Left"
Margin="314,0,0,0"
VerticalAlignment="Top"
Height="34"
Width="75"
FontWeight="Bold" />
<Label x:Name="lblVersion"
Content="Version: "
HorizontalAlignment="Left"
Margin="729,-6,0,0"
VerticalAlignment="Top"
Width="138" />
</Grid>
</Window>

View file

@ -1,656 +0,0 @@
using MediaBrowser.Common;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace MediaBrowser.ServerApplication
{
/// <summary>
/// Interaction logic for LibraryExplorer.xaml
/// </summary>
public partial class LibraryExplorer : Window
{
private readonly ILogger _logger;
private readonly IJsonSerializer _jsonSerializer;
private readonly ILibraryManager _libraryManager;
private readonly IDisplayPreferencesRepository _displayPreferencesManager;
private readonly IItemRepository _itemRepository;
/// <summary>
/// The current user
/// </summary>
private User CurrentUser;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryExplorer" /> class.
/// </summary>
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="logger">The logger.</param>
/// <param name="appHost">The app host.</param>
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="displayPreferencesManager">The display preferences manager.</param>
public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost, IUserManager userManager, ILibraryManager libraryManager, IDisplayPreferencesRepository displayPreferencesManager, IItemRepository itemRepo)
{
_logger = logger;
_jsonSerializer = jsonSerializer;
_libraryManager = libraryManager;
_displayPreferencesManager = displayPreferencesManager;
InitializeComponent();
lblVersion.Content = "Version: " + appHost.ApplicationVersion;
foreach (var user in userManager.Users)
ddlProfile.Items.Add(user);
ddlProfile.Items.Insert(0, new User { Name = "Physical" });
ddlProfile.SelectedIndex = 0;
ddlIndexBy.Visibility = ddlSortBy.Visibility = lblIndexBy.Visibility = lblSortBy.Visibility = Visibility.Hidden;
_itemRepository = itemRepo;
}
/// <summary>
/// Handles the Click event of the btnLoad control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
}
/// <summary>
/// Loads the tree.
/// </summary>
/// <returns>Task.</returns>
private async Task LoadTree()
{
tvwLibrary.Items.Clear();
lblLoading.Visibility = Visibility.Visible;
//grab UI context so we can update within the below task
var ui = TaskScheduler.FromCurrentSynchronizationContext();
//this whole async thing doesn't really work in this instance since all my work pretty much needs to be on the UI thread...
Cursor = Cursors.Wait;
await Task.Run(() =>
{
IEnumerable<BaseItem> children = CurrentUser.Name == "Physical" ? new[] { _libraryManager.RootFolder } : _libraryManager.RootFolder.GetChildren(CurrentUser, true);
children = OrderByName(children, CurrentUser);
foreach (Folder folder in children)
{
var currentFolder = folder;
Task.Factory.StartNew(() =>
{
var prefs = ddlProfile.SelectedItem != null ? _displayPreferencesManager.GetDisplayPreferences(currentFolder.DisplayPreferencesId, (ddlProfile.SelectedItem as User).Id, "LibraryExplorer") ?? new DisplayPreferences { SortBy = ItemSortBy.SortName } : new DisplayPreferences { SortBy = ItemSortBy.SortName };
var node = new TreeViewItem { Tag = currentFolder };
var subChildren = currentFolder.GetChildren(CurrentUser, true);
subChildren = OrderByName(subChildren, CurrentUser);
AddChildren(node, subChildren, CurrentUser);
node.Header = currentFolder.Name + " (" +
node.Items.Count + ")";
tvwLibrary.Items.Add(node);
}, CancellationToken.None, TaskCreationOptions.None, ui);
}
});
lblLoading.Visibility = Visibility.Hidden;
Cursor = Cursors.Arrow;
}
/// <summary>
/// Orders the name of the by.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="user">The user.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> OrderByName(IEnumerable<BaseItem> items, User user)
{
return OrderBy(items, user, ItemSortBy.SortName);
}
/// <summary>
/// Orders the name of the by.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="user">The user.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> OrderBy(IEnumerable<BaseItem> items, User user, string order)
{
return _libraryManager.Sort(items, user, new[] { order }, SortOrder.Ascending);
}
/// <summary>
/// Adds the children.
/// </summary>
/// <param name="parent">The parent.</param>
/// <param name="children">The children.</param>
/// <param name="user">The user.</param>
private void AddChildren(TreeViewItem parent, IEnumerable<BaseItem> children, User user)
{
foreach (var item in children)
{
var node = new TreeViewItem { Tag = item };
var subFolder = item as Folder;
if (subFolder != null)
{
var prefs = _displayPreferencesManager.GetDisplayPreferences(subFolder.DisplayPreferencesId, user.Id, "LibraryExplorer");
AddChildren(node, OrderBy(subFolder.GetChildren(user, true), user, prefs.SortBy), user);
node.Header = item.Name + " (" + node.Items.Count + ")";
}
else
{
node.Header = item.Name;
}
parent.Items.Add(node);
}
}
/// <summary>
/// TVWs the library_ selected item changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
private async void tvwLibrary_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (tvwLibrary.SelectedItem != null)
{
var item = (BaseItem)(tvwLibrary.SelectedItem as TreeViewItem).Tag;
lblObjType.Content = "Type: " + item.GetType().Name;
var movie = item as Movie;
var folder = item as Folder;
if (folder != null)
{
lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Visible;
ddlIndexBy.ItemsSource = folder.IndexByOptionStrings;
ddlSortBy.ItemsSource = new[]
{
ItemSortBy.SortName,
ItemSortBy.Album,
ItemSortBy.AlbumArtist,
ItemSortBy.Artist,
ItemSortBy.CommunityRating,
ItemSortBy.DateCreated,
ItemSortBy.DatePlayed,
ItemSortBy.PremiereDate,
ItemSortBy.ProductionYear,
ItemSortBy.Random,
ItemSortBy.Runtime
};
var prefs = _displayPreferencesManager.GetDisplayPreferences(folder.DisplayPreferencesId, (ddlProfile.SelectedItem as User).Id, "LibraryExplorer");
ddlIndexBy.SelectedItem = prefs != null
? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref")
: LocalizedStrings.Instance.GetString("NoneDispPref");
ddlSortBy.SelectedItem = prefs != null
? prefs.SortBy ?? ItemSortBy.SortName
: ItemSortBy.SortName;
}
else
{
lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Hidden;
}
var json = FormatJson(_jsonSerializer.SerializeToString(item));
if (item is IHasMediaStreams)
{
var mediaStreams = _itemRepository.GetMediaStreams(new MediaStreamQuery
{
ItemId = item.Id
}).ToList();
if (mediaStreams.Count > 0)
{
json += "\n\nMedia Streams:\n\n" + FormatJson(_jsonSerializer.SerializeToString(mediaStreams));
}
}
txtData.Text = json;
var previews = new List<PreviewItem>();
await Task.Run(() =>
{
if (!string.IsNullOrEmpty(item.PrimaryImagePath))
{
previews.Add(new PreviewItem(item.PrimaryImagePath, "Primary"));
}
if (item.HasImage(ImageType.Banner))
{
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Banner), "Banner"));
}
if (item.HasImage(ImageType.Logo))
{
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Logo), "Logo"));
}
if (item.HasImage(ImageType.Art))
{
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Art), "Art"));
}
if (item.HasImage(ImageType.Thumb))
{
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Thumb), "Thumb"));
}
previews.AddRange(
item.GetImages(ImageType.Backdrop).Select(
image => new PreviewItem(image.Path, "Backdrop")));
});
lstPreviews.ItemsSource = previews;
lstPreviews.Items.Refresh();
}
}
/// <summary>
/// The INDEN t_ STRING
/// </summary>
private const string INDENT_STRING = " ";
/// <summary>
/// Formats the json.
/// </summary>
/// <param name="str">The STR.</param>
/// <returns>System.String.</returns>
private static string FormatJson(string str)
{
var indent = 0;
var quoted = false;
var sb = new StringBuilder();
for (var i = 0; i < str.Length; i++)
{
var ch = str[i];
switch (ch)
{
case '{':
case '[':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING));
}
break;
case '}':
case ']':
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING));
}
sb.Append(ch);
break;
case '"':
sb.Append(ch);
bool escaped = false;
var index = i;
while (index > 0 && str[--index] == '\\')
escaped = !escaped;
if (!escaped)
quoted = !quoted;
break;
case ',':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING));
}
break;
case ':':
sb.Append(ch);
if (!quoted)
sb.Append(" ");
break;
default:
sb.Append(ch);
break;
}
}
return sb.ToString();
}
/// <summary>
/// Handles the SelectionChanged event of the ddlProfile control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SelectionChangedEventArgs" /> instance containing the event data.</param>
private void ddlProfile_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CurrentUser = ddlProfile.SelectedItem as User;
if (CurrentUser != null)
LoadTree().ConfigureAwait(false);
}
/// <summary>
/// Handles the Click event of the btnRefresh control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
if (tvwLibrary.SelectedItem != null)
{
var item = ((TreeViewItem)tvwLibrary.SelectedItem).Tag as BaseItem;
if (item != null)
{
item.RefreshMetadata(new MetadataRefreshOptions { ReplaceAllMetadata = cbxForce.IsChecked.Value }, CancellationToken.None);
tvwLibrary_SelectedItemChanged(this, null);
}
}
}
/// <summary>
/// Handles the SelectionChanged event of the ddlIndexBy control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SelectionChangedEventArgs" /> instance containing the event data.</param>
private async void ddlIndexBy_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ddlIndexBy.SelectedItem != null)
{
var treeItem = tvwLibrary.SelectedItem as TreeViewItem;
var folder = treeItem != null
? treeItem.Tag as Folder
: null;
var prefs = folder != null ? _displayPreferencesManager.GetDisplayPreferences(folder.DisplayPreferencesId, CurrentUser.Id, "LibraryExplorer") : new DisplayPreferences { SortBy = ItemSortBy.SortName };
if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string)
{
//grab UI context so we can update within the below task
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Cursor = Cursors.Wait;
await Task.Factory.StartNew(() =>
{
using (
new Profiler("Explorer full index expansion for " +
folder.Name, _logger))
{
//re-build the current item's children as an index
prefs.IndexBy = ddlIndexBy.SelectedItem as string;
treeItem.Items.Clear();
AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, true), CurrentUser, prefs.SortBy), CurrentUser);
treeItem.Header = folder.Name + "(" +
treeItem.Items.Count + ")";
Cursor = Cursors.Arrow;
}
}, CancellationToken.None, TaskCreationOptions.None,
ui);
}
}
}
/// <summary>
/// Handles the SelectionChanged event of the ddlSortBy control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SelectionChangedEventArgs" /> instance containing the event data.</param>
private async void ddlSortBy_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ddlSortBy.SelectedItem != null)
{
var treeItem = tvwLibrary.SelectedItem as TreeViewItem;
var folder = treeItem != null
? treeItem.Tag as Folder
: null;
var prefs = folder != null ? _displayPreferencesManager.GetDisplayPreferences(folder.DisplayPreferencesId, CurrentUser.Id, "LibraryExplorer") : new DisplayPreferences();
if (folder != null && prefs.SortBy != ddlSortBy.SelectedItem as string)
{
//grab UI context so we can update within the below task
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Cursor = Cursors.Wait;
await Task.Factory.StartNew(() =>
{
using (
new Profiler("Explorer sorting by " + ddlSortBy.SelectedItem + " for " +
folder.Name, _logger))
{
//re-sort
prefs.SortBy = ddlSortBy.SelectedItem as string;
treeItem.Items.Clear();
AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, true), CurrentUser, prefs.SortBy ?? ItemSortBy.SortName), CurrentUser);
treeItem.Header = folder.Name + "(" +
treeItem.Items.Count + ")";
Cursor = Cursors.Arrow;
}
}, CancellationToken.None, TaskCreationOptions.None,
ui);
}
}
}
}
/// <summary>
/// Class PreviewItem
/// </summary>
public class PreviewItem
{
/// <summary>
/// The preview
/// </summary>
private readonly string preview;
/// <summary>
/// The name
/// </summary>
private readonly string name;
/// <summary>
/// Gets the preview.
/// </summary>
/// <value>The preview.</value>
public string Preview
{
get { return preview; }
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return name; }
}
/// <summary>
/// Initializes a new instance of the <see cref="PreviewItem" /> class.
/// </summary>
/// <param name="p">The p.</param>
/// <param name="n">The n.</param>
public PreviewItem(string p, string n)
{
preview = p;
name = n;
}
}
/// <summary>
/// Class Extensions
/// </summary>
static class Extensions
{
/// <summary>
/// Fors the each.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ie">The ie.</param>
/// <param name="action">The action.</param>
public static void ForEach<T>(this IEnumerable<T> ie, Action<T> action)
{
foreach (var i in ie)
{
action(i);
}
}
}
#region ItemToImageConverter
/// <summary>
/// Class ItemToImageConverter
/// </summary>
[ValueConversion(typeof(string), typeof(bool))]
public class ItemToImageConverter : IValueConverter
{
/// <summary>
/// The instance
/// </summary>
public static ItemToImageConverter Instance =
new ItemToImageConverter();
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var item = value as BaseItem ?? new Folder();
switch (item.DisplayMediaType)
{
case "DVD":
case "HD DVD":
case "Blu-ray":
case "Blu-Ray":
case "Movie":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/movie.png");
var source = new BitmapImage(uri);
return source;
}
case "Series":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/series.png");
var source = new BitmapImage(uri);
return source;
}
case "Season":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/season.png");
var source = new BitmapImage(uri);
return source;
}
case "Episode":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/episode.png");
var source = new BitmapImage(uri);
return source;
}
case "BoxSet":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/boxset.png");
var source = new BitmapImage(uri);
return source;
}
case "Audio":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/audio.png");
var source = new BitmapImage(uri);
return source;
}
case "Person":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/persons.png");
var source = new BitmapImage(uri);
return source;
}
case "MusicArtist":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/artist.png");
var source = new BitmapImage(uri);
return source;
}
case "MusicAlbum":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/album.png");
var source = new BitmapImage(uri);
return source;
}
case "Trailer":
{
var uri = new Uri
("pack://application:,,,/Resources/Images/trailer.png");
var source = new BitmapImage(uri);
return source;
}
case "None":
{
Uri uri;
if (item is Movie)
uri = new Uri("pack://application:,,,/Resources/Images/movie.png");
else if (item is Series)
uri = new Uri("pack://application:,,,/Resources/Images/series.png");
else if (item is BoxSet)
uri = new Uri("pack://application:,,,/Resources/Images/boxset.png");
else
uri = new Uri("pack://application:,,,/Resources/Images/folder.png");
return new BitmapImage(uri);
}
default:
{
var uri = new Uri("pack://application:,,,/Resources/Images/folder.png");
var source = new BitmapImage(uri);
return source;
}
}
}
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value that is produced by the binding target.</param>
/// <param name="targetType">The type to convert to.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
/// <exception cref="System.NotSupportedException">Cannot convert back</exception>
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException("Cannot convert back");
}
}
#endregion // ItemToImageConverter
}

View file

@ -0,0 +1,127 @@
namespace MediaBrowser.ServerApplication
{
partial class LibraryViewer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LibraryViewer));
this.treeView1 = new System.Windows.Forms.TreeView();
this.txtJson = new System.Windows.Forms.TextBox();
this.panel1 = new System.Windows.Forms.Panel();
this.selectUser = new System.Windows.Forms.ComboBox();
this.lblType = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
// treeView1
//
this.treeView1.Dock = System.Windows.Forms.DockStyle.Left;
this.treeView1.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.treeView1.Location = new System.Drawing.Point(0, 0);
this.treeView1.Name = "treeView1";
this.treeView1.Size = new System.Drawing.Size(260, 517);
this.treeView1.TabIndex = 0;
//
// txtJson
//
this.txtJson.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtJson.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtJson.Location = new System.Drawing.Point(260, 0);
this.txtJson.Multiline = true;
this.txtJson.Name = "txtJson";
this.txtJson.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtJson.Size = new System.Drawing.Size(524, 517);
this.txtJson.TabIndex = 1;
//
// panel1
//
this.panel1.Controls.Add(this.selectUser);
this.panel1.Controls.Add(this.lblType);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(784, 44);
this.panel1.TabIndex = 2;
//
// selectUser
//
this.selectUser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.selectUser.FormattingEnabled = true;
this.selectUser.Location = new System.Drawing.Point(12, 12);
this.selectUser.Name = "selectUser";
this.selectUser.Size = new System.Drawing.Size(121, 21);
this.selectUser.TabIndex = 2;
//
// lblType
//
this.lblType.AutoSize = true;
this.lblType.Location = new System.Drawing.Point(260, 15);
this.lblType.Name = "lblType";
this.lblType.Size = new System.Drawing.Size(0, 13);
this.lblType.TabIndex = 1;
//
// panel2
//
this.panel2.Controls.Add(this.txtJson);
this.panel2.Controls.Add(this.treeView1);
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel2.Location = new System.Drawing.Point(0, 44);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(784, 517);
this.panel2.TabIndex = 3;
//
// LibraryViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(784, 561);
this.Controls.Add(this.panel2);
this.Controls.Add(this.panel1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "LibraryViewer";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Library Explorer";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.panel2.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TreeView treeView1;
private System.Windows.Forms.TextBox txtJson;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.ComboBox selectUser;
private System.Windows.Forms.Label lblType;
private System.Windows.Forms.Panel panel2;
}
}

View file

@ -0,0 +1,243 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
namespace MediaBrowser.ServerApplication
{
public partial class LibraryViewer : Form
{
private readonly IJsonSerializer _jsonSerializer;
private readonly ILibraryManager _libraryManager;
private readonly IDisplayPreferencesRepository _displayPreferencesManager;
private readonly IItemRepository _itemRepository;
private User _currentUser;
public LibraryViewer(IJsonSerializer jsonSerializer, IUserManager userManager, ILibraryManager libraryManager, IDisplayPreferencesRepository displayPreferencesManager, IItemRepository itemRepo)
{
InitializeComponent();
_jsonSerializer = jsonSerializer;
_libraryManager = libraryManager;
_displayPreferencesManager = displayPreferencesManager;
_itemRepository = itemRepo;
foreach (var user in userManager.Users)
selectUser.Items.Add(user);
selectUser.Items.Insert(0, new User { Name = "Physical" });
selectUser.SelectedIndex = 0;
selectUser.SelectedIndexChanged += selectUser_SelectedIndexChanged;
treeView1.AfterSelect += treeView1_AfterSelect;
}
void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
if (e.Node != null)
{
var item = (BaseItem)e.Node.Tag;
lblType.Text = "Type: " + item.GetType().Name;
var json = FormatJson(_jsonSerializer.SerializeToString(item));
if (item is IHasMediaStreams)
{
var mediaStreams = _itemRepository.GetMediaStreams(new MediaStreamQuery
{
ItemId = item.Id
}).ToList();
if (mediaStreams.Count > 0)
{
json += "\n\nMedia Streams:\n\n" + FormatJson(_jsonSerializer.SerializeToString(mediaStreams));
}
}
txtJson.Text = json;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
selectUser_SelectedIndexChanged(null, null);
}
void selectUser_SelectedIndexChanged(object sender, EventArgs e)
{
_currentUser = selectUser.SelectedItem as User;
if (_currentUser != null)
LoadTree();
}
private void LoadTree()
{
treeView1.Nodes.Clear();
IEnumerable<BaseItem> children = _currentUser.Name == "Physical" ? new[] { _libraryManager.RootFolder } : _libraryManager.RootFolder.GetChildren(_currentUser, true);
children = OrderByName(children, _currentUser);
foreach (Folder folder in children)
{
var currentFolder = folder;
var node = new TreeNode { Tag = currentFolder };
var subChildren = currentFolder.GetChildren(_currentUser, true);
subChildren = OrderByName(subChildren, _currentUser);
AddChildren(node, subChildren, _currentUser);
node.Text = currentFolder.Name + " (" +
node.Nodes.Count + ")";
treeView1.Nodes.Add(node);
}
}
/// <summary>
/// Adds the children.
/// </summary>
/// <param name="parent">The parent.</param>
/// <param name="children">The children.</param>
/// <param name="user">The user.</param>
private void AddChildren(TreeNode parent, IEnumerable<BaseItem> children, User user)
{
foreach (var item in children)
{
var node = new TreeNode { Tag = item };
var subFolder = item as Folder;
if (subFolder != null)
{
var prefs = _displayPreferencesManager.GetDisplayPreferences(subFolder.DisplayPreferencesId, user.Id, "LibraryExplorer");
AddChildren(node, OrderBy(subFolder.GetChildren(user, true), user, prefs.SortBy), user);
node.Text = item.Name + " (" + node.Nodes.Count + ")";
}
else
{
node.Text = item.Name;
}
parent.Nodes.Add(node);
}
}
/// <summary>
/// Orders the name of the by.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="user">The user.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> OrderByName(IEnumerable<BaseItem> items, User user)
{
return OrderBy(items, user, ItemSortBy.SortName);
}
/// <summary>
/// Orders the name of the by.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="user">The user.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> OrderBy(IEnumerable<BaseItem> items, User user, string order)
{
return _libraryManager.Sort(items, user, new[] { order }, SortOrder.Ascending);
}
/// <summary>
/// The INDEN t_ STRING
/// </summary>
private const string INDENT_STRING = " ";
/// <summary>
/// Formats the json.
/// </summary>
/// <param name="str">The STR.</param>
/// <returns>System.String.</returns>
private static string FormatJson(string str)
{
var indent = 0;
var quoted = false;
var sb = new StringBuilder();
for (var i = 0; i < str.Length; i++)
{
var ch = str[i];
switch (ch)
{
case '{':
case '[':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING));
}
break;
case '}':
case ']':
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING));
}
sb.Append(ch);
break;
case '"':
sb.Append(ch);
bool escaped = false;
var index = i;
while (index > 0 && str[--index] == '\\')
escaped = !escaped;
if (!escaped)
quoted = !quoted;
break;
case ',':
sb.Append(ch);
if (!quoted)
{
sb.AppendLine();
Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING));
}
break;
case ':':
sb.Append(ch);
if (!quoted)
sb.Append(" ");
break;
default:
sb.Append(ch);
break;
}
}
return sb.ToString();
}
}
/// <summary>
/// Class Extensions
/// </summary>
static class Extensions
{
/// <summary>
/// Fors the each.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ie">The ie.</param>
/// <param name="action">The action.</param>
public static void ForEach<T>(this IEnumerable<T> ie, Action<T> action)
{
foreach (var i in ie)
{
action(i);
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -231,7 +231,7 @@ namespace MediaBrowser.ServerApplication
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
private void cmOpenExplorer_click(object sender, RoutedEventArgs e)
{
new LibraryExplorer(_jsonSerializer, _logger, _appHost, _userManager, _libraryManager, _displayPreferencesManager, _itemRepository).Show();
new LibraryViewer(_jsonSerializer, _userManager, _libraryManager, _displayPreferencesManager, _itemRepository).Show();
}
/// <summary>

View file

@ -170,6 +170,12 @@
<Compile Include="FFMpeg\FFMpegDownloadInfo.cs" />
<Compile Include="FFMpeg\FFMpegInfo.cs" />
<Compile Include="IO\FileSystemFactory.cs" />
<Compile Include="LibraryViewer.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="LibraryViewer.Designer.cs">
<DependentUpon>LibraryViewer.cs</DependentUpon>
</Compile>
<Compile Include="Logging\LogForm.cs">
<SubType>Form</SubType>
</Compile>
@ -197,10 +203,6 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="LibraryExplorer.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -213,9 +215,6 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ApplicationHost.cs" />
<Compile Include="LibraryExplorer.xaml.cs">
<DependentUpon>LibraryExplorer.xaml</DependentUpon>
</Compile>
<Compile Include="Logging\WindowTraceListener.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
@ -240,6 +239,9 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="LibraryViewer.resx">
<DependentUpon>LibraryViewer.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Logging\LogForm.resx">
<DependentUpon>LogForm.cs</DependentUpon>
</EmbeddedResource>