Refactoring and cleanup
This commit is contained in:
@@ -148,6 +148,7 @@ namespace Icarus.Controllers.Managers
|
|||||||
Console.WriteLine($"An Error Occurred: {exMsg}");
|
Console.WriteLine($"An Error Occurred: {exMsg}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveSong(SongData songData)
|
public async Task SaveSong(SongData songData)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -193,8 +194,6 @@ namespace Icarus.Controllers.Managers
|
|||||||
{
|
{
|
||||||
await song.CopyToAsync(fileStream);
|
await song.CopyToAsync(fileStream);
|
||||||
_song.SongPath = filePath;
|
_song.SongPath = filePath;
|
||||||
SaveSongDetails();
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine($"Writing song to the directory: {filePath}");
|
Console.WriteLine($"Writing song to the directory: {filePath}");
|
||||||
Console.WriteLine("Song successfully saved");
|
Console.WriteLine("Song successfully saved");
|
||||||
@@ -250,6 +249,7 @@ namespace Icarus.Controllers.Managers
|
|||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
||||||
{
|
{
|
||||||
cmd.Parameters.AddWithValue("@Id", id);
|
cmd.Parameters.AddWithValue("@Id", id);
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
|
|
||||||
using (MySqlDataAdapter dataDump = new MySqlDataAdapter(cmd))
|
using (MySqlDataAdapter dataDump = new MySqlDataAdapter(cmd))
|
||||||
@@ -264,6 +264,7 @@ namespace Icarus.Controllers.Managers
|
|||||||
var exMsg = ex.Message;
|
var exMsg = ex.Message;
|
||||||
Console.WriteLine($"An error occurred");
|
Console.WriteLine($"An error occurred");
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRow row = results.Rows[0];
|
DataRow row = results.Rows[0];
|
||||||
|
|
||||||
return new Song
|
return new Song
|
||||||
@@ -279,7 +280,7 @@ namespace Icarus.Controllers.Managers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_song = await RetrieveSongDetails(id);
|
_song = await RetrieveSongDetails(id);
|
||||||
song = RetrieveSongFromFileSystem(_song);
|
song = await RetrieveSongFromFileSystem(_song);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -289,32 +290,20 @@ namespace Icarus.Controllers.Managers
|
|||||||
|
|
||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
public async Task<SongData> RetrieveCompressedSong(int id)
|
public async Task<SongData> RetrieveSong(Song songMetaData)
|
||||||
{
|
{
|
||||||
SongData song = new SongData();
|
SongData song = new SongData();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_song = await RetrieveSongDetails(id);
|
Console.WriteLine("Fetching song from filesystem");
|
||||||
Console.WriteLine("Retrieved details of song");
|
song = await RetrieveSongFromFileSystem(songMetaData);
|
||||||
|
|
||||||
song = RetrieveSongFromFileSystem(_song);
|
|
||||||
Console.WriteLine("Retrieved song from filesystem");
|
|
||||||
|
|
||||||
SongCompression compressed = new SongCompression(_archiveDirectoryRoot);
|
|
||||||
Console.WriteLine("SongCompression Initialized");
|
|
||||||
|
|
||||||
var compressedPath = compressed.RetrieveCompressesSongPath(_song);
|
|
||||||
Console.WriteLine($"Path of compressed song: {compressedPath}");
|
|
||||||
|
|
||||||
song.Data = System.IO.File.ReadAllBytes(compressedPath);
|
|
||||||
|
|
||||||
_compressedSongFilename = compressed.CompressedSongFilename;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var exMsg = ex.Message;
|
var exMsg = ex.Message;
|
||||||
Console.WriteLine($"An error occurred: {exMsg}");
|
Console.WriteLine($"An error occurred: {exMsg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +347,7 @@ namespace Icarus.Controllers.Managers
|
|||||||
return _song;
|
return _song;
|
||||||
}
|
}
|
||||||
|
|
||||||
SongData RetrieveSongFromFileSystem(Song details)
|
async Task<SongData> RetrieveSongFromFileSystem(Song details)
|
||||||
{
|
{
|
||||||
byte[] uncompressedSong = System.IO.File.ReadAllBytes(details.SongPath);
|
byte[] uncompressedSong = System.IO.File.ReadAllBytes(details.SongPath);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
using Icarus.Controllers.Managers;
|
||||||
|
using Icarus.Controllers.Utilities;
|
||||||
using Icarus.Models;
|
using Icarus.Models;
|
||||||
|
|
||||||
namespace Icarus.Controllers
|
namespace Icarus.Controllers
|
||||||
@@ -36,8 +37,6 @@ namespace Icarus.Controllers
|
|||||||
_config = config;
|
_config = config;
|
||||||
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
|
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
|
||||||
_archiveDir = _config.GetValue<string>("ArchivePath");
|
_archiveDir = _config.GetValue<string>("ArchivePath");
|
||||||
_songMgr = new SongManager(config, _songTempDir);
|
|
||||||
_songMgr.ArchiveDirectoryRoot = _archiveDir;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -46,14 +45,16 @@ namespace Icarus.Controllers
|
|||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<IActionResult> Get(int id)
|
public async Task<IActionResult> Get(int id)
|
||||||
{
|
{
|
||||||
SongData song = new SongData();
|
MusicStoreContext context = HttpContext.RequestServices.GetService(typeof(MusicStoreContext)) as MusicStoreContext;
|
||||||
|
|
||||||
|
SongCompression cmp = new SongCompression(_archiveDir);
|
||||||
|
|
||||||
Console.WriteLine($"Archive directory root: {_archiveDir}");
|
Console.WriteLine($"Archive directory root: {_archiveDir}");
|
||||||
|
|
||||||
Console.WriteLine("Starting process of retrieving comrpessed song");
|
Console.WriteLine("Starting process of retrieving comrpessed song");
|
||||||
song = await _songMgr.RetrieveCompressedSong(id);
|
SongData song = await cmp.RetrieveCompressedSong(context.GetSong(id));
|
||||||
|
|
||||||
return File(song.Data, "application/x-msdownload", _songMgr.CompressedSongFilename);
|
return File(song.Data, "application/x-msdownload", cmp.CompressedSongFilename);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ namespace Icarus.Controllers
|
|||||||
{
|
{
|
||||||
List<Song> songs = new List<Song>();
|
List<Song> songs = new List<Song>();
|
||||||
songs = _songMgr.RetrieveAllSongDetails().Result;
|
songs = _songMgr.RetrieveAllSongDetails().Result;
|
||||||
|
Console.WriteLine("Attemtping to retrieve songs");
|
||||||
|
|
||||||
|
MusicStoreContext context = HttpContext.RequestServices.GetService(typeof(MusicStoreContext)) as MusicStoreContext;
|
||||||
|
|
||||||
|
songs = context.GetAllSongs();
|
||||||
|
|
||||||
|
|
||||||
return songs;
|
return songs;
|
||||||
@@ -48,7 +53,8 @@ namespace Icarus.Controllers
|
|||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public ActionResult<Song> Get(int id)
|
public ActionResult<Song> Get(int id)
|
||||||
{
|
{
|
||||||
Song song = _songMgr.RetrieveSongDetails(id).Result;
|
MusicStoreContext context = HttpContext.RequestServices.GetService(typeof(MusicStoreContext)) as MusicStoreContext;
|
||||||
|
Song song = context.GetSong(id);
|
||||||
|
|
||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
@@ -56,6 +62,7 @@ namespace Icarus.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public void Post([FromBody] Song song)
|
public void Post([FromBody] Song song)
|
||||||
{
|
{
|
||||||
|
// TODO: Replace this call with the one in the MusicContext class
|
||||||
_songMgr.SaveSongDetails(song);
|
_songMgr.SaveSongDetails(song);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,11 +51,12 @@ namespace Icarus.Controllers
|
|||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<IActionResult> Get(int id)
|
public async Task<IActionResult> Get(int id)
|
||||||
{
|
{
|
||||||
SongData song = new SongData();
|
MusicStoreContext context = HttpContext.RequestServices.GetService(typeof(MusicStoreContext)) as MusicStoreContext;
|
||||||
|
var songMetaData = context.GetSong(id);
|
||||||
|
|
||||||
song = await _songMgr.RetrieveSong(id);
|
SongData song = await _songMgr.RetrieveSong(songMetaData);
|
||||||
|
|
||||||
return File(song.Data, "application/x-msdownload", _songMgr.SongDetails.Filename);
|
return File(song.Data, "application/x-msdownload", songMetaData.Filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -63,6 +64,7 @@ namespace Icarus.Controllers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
MusicStoreContext context = HttpContext.RequestServices.GetService(typeof(MusicStoreContext)) as MusicStoreContext;
|
||||||
Console.WriteLine("Uploading song...");
|
Console.WriteLine("Uploading song...");
|
||||||
|
|
||||||
var uploads = _songTempDir;
|
var uploads = _songTempDir;
|
||||||
@@ -71,6 +73,9 @@ namespace Icarus.Controllers
|
|||||||
{
|
{
|
||||||
if (sng.Length > 0) {
|
if (sng.Length > 0) {
|
||||||
await _songMgr.SaveSongToFileSystem(sng);
|
await _songMgr.SaveSongToFileSystem(sng);
|
||||||
|
var song = _songMgr.SongDetails;
|
||||||
|
context.SaveSong(song);
|
||||||
|
Console.WriteLine("Song successfully saved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
using Ionic.Zip;
|
using Ionic.Zip;
|
||||||
|
|
||||||
using Icarus.Models;
|
using Icarus.Models;
|
||||||
@@ -11,6 +13,7 @@ namespace Icarus.Controllers.Utilities
|
|||||||
public class SongCompression
|
public class SongCompression
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
string _archiveDirectory;
|
||||||
string _compressedSongFilename;
|
string _compressedSongFilename;
|
||||||
string _tempDirectory;
|
string _tempDirectory;
|
||||||
byte[] _uncompressedSong;
|
byte[] _uncompressedSong;
|
||||||
@@ -42,6 +45,25 @@ namespace Icarus.Controllers.Utilities
|
|||||||
|
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
public async Task<SongData> RetrieveCompressedSong(Song song)
|
||||||
|
{
|
||||||
|
SongData songData = new SongData();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var archivePath = RetrieveCompressesSongPath(song);
|
||||||
|
Console.WriteLine($"Compressed song saved to: {archivePath}");
|
||||||
|
|
||||||
|
songData.Data = System.IO.File.ReadAllBytes(archivePath);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error ocurred: \n{exMsg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return songData;
|
||||||
|
}
|
||||||
|
|
||||||
public string RetrieveCompressesSongPath(Song songDetails)
|
public string RetrieveCompressesSongPath(Song songDetails)
|
||||||
{
|
{
|
||||||
string tmpZipFilePath = _tempDirectory + songDetails.Filename;
|
string tmpZipFilePath = _tempDirectory + songDetails.Filename;
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Icarus.Models
|
||||||
|
{
|
||||||
|
public class MusicStoreContext
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
|
||||||
|
public MusicStoreContext(string connectionString)
|
||||||
|
{
|
||||||
|
this.ConnectionString = connectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertSongDetails()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SaveSong(Song song)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (MySqlConnection conn = GetConnection())
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
string query = "INSERT INTO Songs(Title, Album, Artist, Year, Genre, Duration, " +
|
||||||
|
"Filename, SongPath) VALUES(@Title, @Album, @Artist, @Year, @Genre, " +
|
||||||
|
"@Duration, @Filename, @SongPath)";
|
||||||
|
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@Title", song.Title);
|
||||||
|
cmd.Parameters.AddWithValue("@Album", song.Album);
|
||||||
|
cmd.Parameters.AddWithValue("@Artist", song.Artist);
|
||||||
|
cmd.Parameters.AddWithValue("@Year", song.Year);
|
||||||
|
cmd.Parameters.AddWithValue("@Genre", song.Genre);
|
||||||
|
cmd.Parameters.AddWithValue("@Duration", song.Duration);
|
||||||
|
cmd.Parameters.AddWithValue("@Filename", song.Filename);
|
||||||
|
cmd.Parameters.AddWithValue("@SongPath", song.SongPath);
|
||||||
|
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error occurred:\n{exMsg}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Song> GetAllSongs()
|
||||||
|
{
|
||||||
|
List<Song> songs = new List<Song>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (MySqlConnection conn = GetConnection())
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
var query = "SELECT * FROM Songs";
|
||||||
|
MySqlCommand cmd = new MySqlCommand(query, conn);
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
songs.Add(new Song
|
||||||
|
{
|
||||||
|
Id = Convert.ToInt32(reader["Id"]),
|
||||||
|
Title = reader["Title"].ToString(),
|
||||||
|
Album = reader["Album"].ToString(),
|
||||||
|
Artist = reader["Artist"].ToString(),
|
||||||
|
Year = Convert.ToInt32(reader["Year"]),
|
||||||
|
Genre = reader["Genre"].ToString(),
|
||||||
|
Duration = Convert.ToInt32(reader["Duration"]),
|
||||||
|
Filename = reader["Filename"].ToString(),
|
||||||
|
SongPath = reader["SongPath"].ToString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error ocurred:\n{exMsg}");
|
||||||
|
songs.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return songs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Song GetSong(int id)
|
||||||
|
{
|
||||||
|
Song song = new Song();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (MySqlConnection conn = GetConnection())
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
var query = "SELECT * FROM Songs WHERE Id=@Id";
|
||||||
|
|
||||||
|
MySqlCommand cmd = new MySqlCommand(query, conn);
|
||||||
|
cmd.Parameters.AddWithValue("@Id", id);
|
||||||
|
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
song = new Song
|
||||||
|
{
|
||||||
|
Id = Convert.ToInt32(reader["Id"]),
|
||||||
|
Title = reader["Title"].ToString(),
|
||||||
|
Album = reader["Album"].ToString(),
|
||||||
|
Artist = reader["Artist"].ToString(),
|
||||||
|
Year = Convert.ToInt32(reader["Year"]),
|
||||||
|
Genre = reader["Genre"].ToString(),
|
||||||
|
Duration = Convert.ToInt32(reader["Duration"]),
|
||||||
|
Filename = reader["Filename"].ToString(),
|
||||||
|
SongPath = reader["SongPath"].ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error ocurred: {exMsg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MySqlConnection GetConnection()
|
||||||
|
{
|
||||||
|
return new MySqlConnection(ConnectionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,9 @@ namespace Icarus.Models
|
|||||||
{
|
{
|
||||||
public class Song
|
public class Song
|
||||||
{
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
private MusicStoreContext _context;
|
||||||
|
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
[JsonProperty("title")]
|
[JsonProperty("title")]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.HttpsPolicy;
|
using Microsoft.AspNetCore.HttpsPolicy;
|
||||||
@@ -11,6 +12,8 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
namespace Icarus
|
namespace Icarus
|
||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
@@ -27,6 +30,8 @@ namespace Icarus
|
|||||||
{
|
{
|
||||||
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||||
services.AddSingleton<IConfiguration>(Configuration);
|
services.AddSingleton<IConfiguration>(Configuration);
|
||||||
|
|
||||||
|
services.Add(new ServiceDescriptor(typeof(MusicStoreContext), new MusicStoreContext(Configuration.GetConnectionString("DefaultConnection"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"IcarusDev":"Server=; User=; Password=; Database=; Port="
|
"DefaultConnection":"Server=;Database=;Uid=;Pwd=;"
|
||||||
},
|
},
|
||||||
"RootMusicPath":"/root/of/music/path/",
|
"RootMusicPath":"/music/path/",
|
||||||
"TemporaryMusicPath":"/root/temp/music/path/",
|
"TemporaryMusicPath":"/music/temp/path/",
|
||||||
"ArchivePath":"/root/of/archive/path/"
|
"ArchivePath":"/archive/path/"
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -6,9 +6,9 @@
|
|||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"IcarusProd":"Server=; User=; Password=; Database=; Port="
|
"DefaultConnection":"Server=;Database=;Uid=;Pwd=;"
|
||||||
},
|
},
|
||||||
"RootMusicPath":"/root/of/music/path/",
|
"RootMusicPath":"/music/path/",
|
||||||
"TemporaryMusicPath":"/root/temp/music/path/",
|
"TemporaryMusicPath":"/music/temp/path/",
|
||||||
"ArchivePath":"/root/of/archive/path/"
|
"ArchivePath":"/archive/path/"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user