Merge pull request #4 from ganjoor/audioman

Audioman
This commit is contained in:
Hamid Reza Mohammadi 2020-08-30 12:19:23 +04:30 committed by GitHub
commit 35f29649ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1726 additions and 5 deletions

View File

@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RMuseum.Models.Auth.Memory;
using RMuseum.Services;
using RSecurityBackend.Models.Generic;
using RSecurityBackend.Services;
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace RMuseum.Controllers
{
[Produces("application/json")]
[Route("api/audio")]
public class AudioNarrationController : Controller
{
/// <summary>
/// imports data from ganjoor MySql database
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("mysqlonetimeimport")]
[Authorize(Policy = RMuseumSecurableItem.AudioNarrationEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)]
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))]
[ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))]
public async Task<IActionResult> MysqlonetimeImport()
{
Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value);
RServiceResult<bool> res =
await _audioService.OneTimeImport(loggedOnUserId);
if (res.Result)
return Ok();
return BadRequest(res.ExceptionString);
}
/// <summary>
/// constructor
/// </summary>
/// <param name="audioService">
/// </param>
/// <param name="userPermissionChecker"></param>
public AudioNarrationController(IAudioNarrationService audioService, IUserPermissionChecker userPermissionChecker)
{
_audioService = audioService;
_userPermissionChecker = userPermissionChecker;
}
/// <summary>
/// Artifact Service
/// </summary>
protected readonly IAudioNarrationService _audioService;
/// <summary>
/// IUserPermissionChecker instance
/// </summary>
protected IUserPermissionChecker _userPermissionChecker;
}
}

View File

@ -2,6 +2,7 @@
using Microsoft.Extensions.Configuration;
using RMuseum.Models.Artifact;
using RMuseum.Models.Bookmark;
using RMuseum.Models.GanjoorAudio;
using RMuseum.Models.GanjoorIntegration;
using RMuseum.Models.ImportJob;
using RMuseum.Models.Note;
@ -126,5 +127,10 @@ namespace RMuseum.DbContext
/// </summary>
public DbSet<PinterestLink> PinterestLinks { get; set; }
/// <summary>
/// Ganjoor Audio Files
/// </summary>
public DbSet<PoemNarration> AudioFiles { get; set; }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace RMuseum.Migrations
{
public partial class AudioFiles : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AudioFiles",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
OwnerId = table.Column<Guid>(nullable: false),
GanjoorAudioId = table.Column<int>(nullable: false),
GanjoorPostId = table.Column<int>(nullable: false),
AudioOrder = table.Column<int>(nullable: false),
FileNameWithoutExtension = table.Column<string>(nullable: true),
SoundFilesFolder = table.Column<string>(nullable: true),
AudioTitle = table.Column<string>(nullable: true),
AudioArtist = table.Column<string>(nullable: true),
AudioArtistUrl = table.Column<string>(nullable: true),
AudioSrc = table.Column<string>(nullable: true),
AudioSrcUrl = table.Column<string>(nullable: true),
LegacyAudioGuid = table.Column<Guid>(nullable: false),
Mp3FileCheckSum = table.Column<string>(nullable: true),
Mp3SizeInBytes = table.Column<int>(nullable: false),
OggSizeInBytes = table.Column<int>(nullable: false),
UploadDate = table.Column<DateTime>(nullable: false),
ReviewDate = table.Column<DateTime>(nullable: false),
LocalMp3FilePath = table.Column<string>(nullable: true),
LocalXmlFilePath = table.Column<string>(nullable: true),
AudioSyncStatus = table.Column<int>(nullable: false),
ReviewStatus = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AudioFiles", x => x.Id);
table.ForeignKey(
name: "FK_AudioFiles_AspNetUsers_OwnerId",
column: x => x.OwnerId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AudioFiles_OwnerId",
table: "AudioFiles",
column: "OwnerId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AudioFiles");
}
}
}

View File

@ -336,6 +336,82 @@ namespace RMuseum.Migrations
b.ToTable("UserBookmarks");
});
modelBuilder.Entity("RMuseum.Models.GanjoorAudio.PoemNarration", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("AudioArtist")
.HasColumnType("nvarchar(max)");
b.Property<string>("AudioArtistUrl")
.HasColumnType("nvarchar(max)");
b.Property<int>("AudioOrder")
.HasColumnType("int");
b.Property<string>("AudioSrc")
.HasColumnType("nvarchar(max)");
b.Property<string>("AudioSrcUrl")
.HasColumnType("nvarchar(max)");
b.Property<int>("AudioSyncStatus")
.HasColumnType("int");
b.Property<string>("AudioTitle")
.HasColumnType("nvarchar(max)");
b.Property<string>("FileNameWithoutExtension")
.HasColumnType("nvarchar(max)");
b.Property<int>("GanjoorAudioId")
.HasColumnType("int");
b.Property<int>("GanjoorPostId")
.HasColumnType("int");
b.Property<Guid>("LegacyAudioGuid")
.HasColumnType("uniqueidentifier");
b.Property<string>("LocalMp3FilePath")
.HasColumnType("nvarchar(max)");
b.Property<string>("LocalXmlFilePath")
.HasColumnType("nvarchar(max)");
b.Property<string>("Mp3FileCheckSum")
.HasColumnType("nvarchar(max)");
b.Property<int>("Mp3SizeInBytes")
.HasColumnType("int");
b.Property<int>("OggSizeInBytes")
.HasColumnType("int");
b.Property<Guid>("OwnerId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("ReviewDate")
.HasColumnType("datetime2");
b.Property<int>("ReviewStatus")
.HasColumnType("int");
b.Property<string>("SoundFilesFolder")
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("UploadDate")
.HasColumnType("datetime2");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.ToTable("AudioFiles");
});
modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.GanjoorLink", b =>
{
b.Property<Guid>("Id")
@ -1054,6 +1130,15 @@ namespace RMuseum.Migrations
.HasForeignKey("RArtifactMasterRecordId");
});
modelBuilder.Entity("RMuseum.Models.GanjoorAudio.PoemNarration", b =>
{
b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.GanjoorLink", b =>
{
b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", "Artifact")

View File

@ -58,6 +58,11 @@ namespace RMuseum.Models.Auth.Memory
/// </summary>
public const string ReviewGanjoorLinksOperationShortName = "ganjoor";
/// <summary>
/// audio narrations
/// </summary>
public const string AudioNarrationEntityShortName = "narration";
/// <summary>
/// list of forms and their permissions
/// </summary>
@ -106,6 +111,16 @@ namespace RMuseum.Models.Auth.Memory
new SecurableItemOperation(ModerateCommentsOperationShortName, "بررسی", false)
}
},
new SecurableItem()
{
ShortName = AudioNarrationEntityShortName,
Description = "خوانشها",
Operations = new SecurableItemOperation[]
{
new SecurableItemOperation(ImportOperationShortName, "ورود اطلاعات", false),
new SecurableItemOperation(ModerateCommentsOperationShortName, "بررسی", false)
}
},
});
return lst.ToArray();

View File

@ -21,7 +21,7 @@
MetadataChanged = 2,
/// <summary>
/// sound files should be reuploaded
/// sound files should be reuploaded (this means xml file is also needs to reuploaded)
/// </summary>
SoundFilesChanged = 4,
@ -31,7 +31,7 @@
XmlFileChanged = 8,
/// <summary>
/// Item is deleted
/// Item should be deleted
/// </summary>
Deleted = 16

View File

@ -82,6 +82,11 @@ namespace RMuseum.Models.GanjoorAudio
/// <sample>
/// "/i/a2/x"
/// </sample>
/// <remarks>
/// XML Schema is defined based on Desktop Ganjoor (https://github.com/ganjoor/ganjoor) code, for
/// more information take a look at this code:
/// https://github.com/ganjoor/ganjoor/blob/master/ganjoor/Audio%20Support/PoemAudioListProcessor.cs
/// </remarks>
public string RemoteXMLFilePath { get { return $"/i/{SoundFilesFolder}/x/{FileNameWithoutExtension}.xml"; } }
/// <summary>

View File

@ -18,6 +18,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MySql.Data" Version="8.0.21" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="5.0.2" />

View File

@ -620,6 +620,30 @@
Captcha service
</summary>
</member>
<member name="M:RMuseum.Controllers.AudioNarrationController.MysqlonetimeImport">
<summary>
imports data from ganjoor MySql database
</summary>
<returns></returns>
</member>
<member name="M:RMuseum.Controllers.AudioNarrationController.#ctor(RMuseum.Services.IAudioNarrationService,RSecurityBackend.Services.IUserPermissionChecker)">
<summary>
constructor
</summary>
<param name="audioService">
</param>
<param name="userPermissionChecker"></param>
</member>
<member name="F:RMuseum.Controllers.AudioNarrationController._audioService">
<summary>
Artifact Service
</summary>
</member>
<member name="F:RMuseum.Controllers.AudioNarrationController._userPermissionChecker">
<summary>
IUserPermissionChecker instance
</summary>
</member>
<member name="T:RMuseum.Controllers.AuditLogController">
<summary>
Audit Log Controller Base
@ -776,6 +800,11 @@
Pinterest Links
</summary>
</member>
<member name="P:RMuseum.DbContext.RMuseumDbContext.AudioFiles">
<summary>
Ganjoor Audio Files
</summary>
</member>
<member name="T:RMuseum.Models.Artifact.PublishStatus">
<summary>
Items or pictures status
@ -1385,6 +1414,11 @@
review suggested ganjoor links
</summary>
</member>
<member name="F:RMuseum.Models.Auth.Memory.RMuseumSecurableItem.AudioNarrationEntityShortName">
<summary>
audio narrations
</summary>
</member>
<member name="P:RMuseum.Models.Auth.Memory.RMuseumSecurableItem.Items">
<summary>
list of forms and their permissions
@ -1537,7 +1571,7 @@
</member>
<member name="F:RMuseum.Models.GanjoorAudio.AudioSyncStatus.SoundFilesChanged">
<summary>
sound files should be reuploaded
sound files should be reuploaded (this means xml file is also needs to reuploaded)
</summary>
</member>
<member name="F:RMuseum.Models.GanjoorAudio.AudioSyncStatus.XmlFileChanged">
@ -1547,7 +1581,7 @@
</member>
<member name="F:RMuseum.Models.GanjoorAudio.AudioSyncStatus.Deleted">
<summary>
Item is deleted
Item should be deleted
</summary>
</member>
<member name="T:RMuseum.Models.GanjoorAudio.PoemNarration">
@ -1628,6 +1662,11 @@
<sample>
"/i/a2/x"
</sample>
<remarks>
XML Schema is defined based on Desktop Ganjoor (https://github.com/ganjoor/ganjoor) code, for
more information take a look at this code:
https://github.com/ganjoor/ganjoor/blob/master/ganjoor/Audio%20Support/PoemAudioListProcessor.cs
</remarks>
</member>
<member name="P:RMuseum.Models.GanjoorAudio.PoemNarration.AudioTitle">
<summary>
@ -2985,6 +3024,18 @@
<param name="checkJobs"></param>
<returns></returns>
</member>
<member name="T:RMuseum.Services.IAudioNarrationService">
<summary>
Audio Narration Service
</summary>
</member>
<member name="M:RMuseum.Services.IAudioNarrationService.OneTimeImport(System.Guid)">
<summary>
imports data from ganjoor MySql database
</summary>
<param name="OwnrRAppUserId">User Id which becomes owner of imported data</param>
<returns></returns>
</member>
<member name="T:RMuseum.Services.Implementation.ArtifactService">
<summary>
IArtifactService implementation
@ -3693,6 +3744,34 @@
<param name="backgroundTaskQueue"></param>
<param name="userService"></param>
</member>
<member name="T:RMuseum.Services.Implementation.AudioNarrationService">
<summary>
Audio Narration Service Implementation
</summary>
</member>
<member name="M:RMuseum.Services.Implementation.AudioNarrationService.OneTimeImport(System.Guid)">
<summary>
imports data from ganjoor MySql database
</summary>
<param name="OwnrRAppUserId">User Id which becomes owner of imported data</param>
</member>
<member name="P:RMuseum.Services.Implementation.AudioNarrationService.Configuration">
<summary>
Configuration
</summary>
</member>
<member name="F:RMuseum.Services.Implementation.AudioNarrationService._context">
<summary>
Database Contetxt
</summary>
</member>
<member name="M:RMuseum.Services.Implementation.AudioNarrationService.#ctor(RMuseum.DbContext.RMuseumDbContext,Microsoft.Extensions.Configuration.IConfiguration)">
<summary>
constructor
</summary>
<param name="context"></param>
<param name="configuration"></param>
</member>
<member name="T:RMuseum.Services.Implementation.BLTileMixer">
<summary>
British Library Tile Downloader And Mixer

View File

@ -0,0 +1,19 @@
using RSecurityBackend.Models.Generic;
using System;
using System.Threading.Tasks;
namespace RMuseum.Services
{
/// <summary>
/// Audio Narration Service
/// </summary>
public interface IAudioNarrationService
{
/// <summary>
/// imports data from ganjoor MySql database
/// </summary>
/// <param name="OwnrRAppUserId">User Id which becomes owner of imported data</param>
/// <returns></returns>
Task<RServiceResult<bool>> OneTimeImport(Guid OwnrRAppUserId);
}
}

View File

@ -0,0 +1,118 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using MySql.Data.MySqlClient;
using RMuseum.DbContext;
using RMuseum.Models.GanjoorAudio;
using RSecurityBackend.Models.Generic;
using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Threading.Tasks;
namespace RMuseum.Services.Implementation
{
/// <summary>
/// Audio Narration Service Implementation
/// </summary>
public class AudioNarrationService : IAudioNarrationService
{
/// <summary>
/// imports data from ganjoor MySql database
/// </summary>
/// <param name="OwnrRAppUserId">User Id which becomes owner of imported data</param>
public async Task<RServiceResult<bool>> OneTimeImport(Guid OwnrRAppUserId)
{
try
{
PoemNarration sampleCheck = await _context.AudioFiles.FirstOrDefaultAsync();
if(sampleCheck != null)
{
return new RServiceResult<bool>(false, "OneTimeImport is a one time operation and cannot be called multiple times.");
}
using (MySqlConnection connection = new MySqlConnection
(
$"server={Configuration.GetSection("AudioMySqlServer")["Server"]};uid={Configuration.GetSection("AudioMySqlServer")["Username"]};pwd={Configuration.GetSection("AudioMySqlServer")["Password"]};database={Configuration.GetSection("AudioMySqlServer")["Database"]};charset=utf8"
))
{
connection.Open();
using(MySqlDataAdapter src = new MySqlDataAdapter(
"SELECT audio_ID, audio_post_ID, audio_order, audio_xml, audio_ogg, audio_mp3, " +
"audio_title, audio_artist, audio_artist_url, audio_src, audio_src_url, audio_guid, " +
"audio_fchecksum, audio_mp3bsize, audio_oggbsize, audio_date " +
"FROM adab.ganja_gaudio ORDER BY audio_ID",
connection
))
{
using(DataTable srcData = new DataTable())
{
await src.FillAsync(srcData);
int audioSyncStatus = (int)AudioSyncStatus.SynchronizedOrRejected;
foreach (DataRow row in srcData.Rows)
{
PoemNarration newRecord = new PoemNarration()
{
OwnerId = OwnrRAppUserId,
GanjoorAudioId = int.Parse(row["audio_ID"].ToString()),
GanjoorPostId = (int)row["audio_post_ID"],
AudioOrder = (int)row["audio_order"],
AudioTitle = row["audio_title"].ToString(),
AudioArtist = row["audio_artist"].ToString(),
AudioArtistUrl = row["audio_artist_url"].ToString(),
AudioSrc = row["audio_src"].ToString(),
AudioSrcUrl = row["audio_src_url"].ToString(),
LegacyAudioGuid = new Guid(row["audio_guid"].ToString()),
Mp3FileCheckSum = row["audio_fchecksum"].ToString(),
Mp3SizeInBytes = (int)row["audio_mp3bsize"],
OggSizeInBytes = (int)row["audio_oggbsize"],
UploadDate = (DateTime)row["audio_date"],
AudioSyncStatus = audioSyncStatus,
ReviewStatus = AudioReviewStatus.Approved
};
newRecord.ReviewDate = newRecord.UploadDate;
string audio_xml = row["audio_xml"].ToString();
//sample audio_xml value: /i/a/x/11876-Simorgh.xml
audio_xml = audio_xml.Substring("/i/".Length); // /i/a/x/11876-Simorgh.xml -> a/x/11876-Simorgh.xml
newRecord.SoundFilesFolder = audio_xml.Substring(0, audio_xml.IndexOf('/')); //(a)
newRecord.FileNameWithoutExtension = Path.GetFileNameWithoutExtension(audio_xml.Substring(audio_xml.LastIndexOf('/') + 1)); //(11876-Simorgh)
_context.AudioFiles.Add(newRecord);
}
}
await _context.SaveChangesAsync();
}
}
return new RServiceResult<bool>(true);
}
catch(Exception exp)
{
return new RServiceResult<bool>(false, exp.ToString());
}
}
/// <summary>
/// Configuration
/// </summary>
protected IConfiguration Configuration { get; }
/// <summary>
/// Database Contetxt
/// </summary>
protected readonly RMuseumDbContext _context;
/// <summary>
/// constructor
/// </summary>
/// <param name="context"></param>
/// <param name="configuration"></param>
public AudioNarrationService(RMuseumDbContext context, IConfiguration configuration)
{
_context = context;
Configuration = configuration;
}
}
}

View File

@ -248,6 +248,9 @@ namespace RMuseum
//artifact service
services.AddTransient<IArtifactService, ArtifactService>();
//audio service
services.AddTransient<IAudioNarrationService, AudioNarrationService>();
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();

View File

@ -33,6 +33,11 @@
"Password": "password",
"From": "test@gmail.com"
},
"AudioMySqlServer": {
"Server": "localhost",
"Username": "root",
"Password": "",
"Database": "adab"
},
"AllowedHosts": "*"
}