private void ScanForSpeakerInfo(SubscriptionInfo subscriptionInfo, string recordingsFolder, bool restricted, int progressFrom, int progressTo) { ILookup <string, DirectoryInfoBase> directories = _fileSystem.DirectoryInfo.FromDirectoryName(recordingsFolder) .GetDirectories("*", SearchOption.AllDirectories) .ToLookup(d => d.Name); using (IDbConnection db = _dbConnectionFactory.Open()) using (IDbTransaction transaction = db.OpenTransaction()) { List <DbSpeaker> speakers = db.Select <DbSpeaker>(); for (int index = 0; index < speakers.Count; index++) { DbSpeaker speaker = speakers[index]; string fullName = speaker.ToSpeaker().FullName; if (directories.Contains(fullName)) { FileInfoBase photo = directories[fullName] .SelectMany(d => d.GetFiles("*.jpg")) .OrderByDescending(f => f.Length) .FirstOrDefault(); if (photo != null) { speaker.PhotoPath = photo.FullName; db.Update(speaker); } FileInfoBase markdownFile = directories[fullName] .SelectMany(d => d.GetFiles("*.md")) .OrderByDescending(f => f.Length) .FirstOrDefault(); if (markdownFile != null) { string markdownText = _fileSystem.File.ReadAllText(markdownFile.FullName); speaker.Description = new Markdown().Transform(markdownText); } if (markdownFile != null || photo != null) { db.Update(speaker); } } PublishProgress(subscriptionInfo, (progressTo - progressFrom) * (index / speakers.Count)); } transaction.Commit(); } }
private void RebuildFromFolder(SubscriptionInfo subscriptionInfo, string folderPath, bool restricted, int startPercent = 0, int endPercent = 100) { if (folderPath == null) { throw new ArgumentNullException(nameof(folderPath)); } using (IDbConnection db = _dbConnectionFactory.Open()) { DirectoryInfoBase directoryInfo = _fileSystem.DirectoryInfo.FromDirectoryName(folderPath); FileInfoBase[] files = directoryInfo.GetFiles("*.mp3", SearchOption.AllDirectories); int index = 0; foreach (IGrouping <string, FileInfoBase> albumFiles in files.GroupBy(f => f.DirectoryName)) { using (IDbTransaction transaction = db.OpenTransaction()) { _logger.Debug("Fetching album"); DbAlbum album = db.Single <DbAlbum>(a => a.Path == albumFiles.Key); foreach (FileInfoBase file in albumFiles) { int progress = (int)Math.Round((index + 1) / (double)files.Length * (endPercent - startPercent)) + startPercent; PublishProgress(subscriptionInfo, progress); _logger.DebugFormat("Processing file {0}", file.FullName); DbRecording recording; bool saveTagFile = false; _logger.Debug("Reading tag file"); using (File tagFile = File.Create(_fileAbstractionFactory(file.FullName, true))) { string recordingId = tagFile.GetCustomField(SoundWordsRecordingIdField); if (recordingId != null) { _logger.Debug("Fetching recording"); recording = db.Single <DbRecording>(r => r.Uid == recordingId) ?? new DbRecording { Uid = recordingId }; } else { recording = new DbRecording { Uid = Guid.NewGuid().ToString("N") }; saveTagFile = true; tagFile.SetCustomField(SoundWordsRecordingIdField, recording.Uid); } if (album == null) { string uid = tagFile.GetCustomField(SoundWordsAlbumIdField) ?? Guid.NewGuid().ToString("N"); album = new DbAlbum { Uid = uid, Name = (tagFile.Tag.Album ?? "Ukjent").Trim(), Path = albumFiles.Key, Restricted = restricted }; } UpdateAttachments(albumFiles.Key, album); if (album.Id != 0) { _logger.Debug("Saving album"); db.Update(album); } else { _logger.Debug("Creating album"); album.Id = db.Insert(album, true); } if (tagFile.GetCustomField(SoundWordsAlbumIdField) != album.Uid) { tagFile.SetCustomField(SoundWordsAlbumIdField, album.Uid); saveTagFile = true; } recording.AlbumId = album.Id; recording.Title = (tagFile.Tag.Title ?? "Ukjent").Trim(); recording.Track = (ushort)tagFile.Tag.Track; recording.Comment = tagFile.Tag.Comment; recording.Year = tagFile.Tag.Year != 0 ? (ushort?)tagFile.Tag.Year : null; recording.Path = file.FullName; recording.Restricted = restricted; if (recording.Id == 0) { _logger.DebugFormat("Creating recording: {0}", recording.Dump()); recording.Id = db.Insert(recording, true); } else { _logger.DebugFormat("Saving recording: {0}", recording.Dump()); db.Update(recording); } db.Delete <DbRecordingSpeaker>(rs => rs.RecordingId == recording.Id); foreach (string performer in tagFile.Tag.Performers) { _logger.DebugFormat($"Creating speaker {performer}"); NameInfo nameInfo = performer.ToNameInfo(); DbSpeaker speaker = db.Single <DbSpeaker>(s => s.FirstName == nameInfo.FirstName && s.LastName == nameInfo.LastName); if (speaker == null) { speaker = new DbSpeaker { Uid = Guid.NewGuid().ToString("N"), FirstName = nameInfo.FirstName, LastName = nameInfo.LastName }; speaker.Id = db.Insert(speaker, true); } if (!db.Exists <DbRecordingSpeaker>(rs => rs.RecordingId == recording.Id && rs.SpeakerId == speaker.Id)) { db.Insert(new DbRecordingSpeaker { RecordingId = recording.Id, SpeakerId = speaker.Id }); } } if (saveTagFile) { _logger.Debug("Writing ID tag data"); tagFile.Save(); } } index++; } _logger.Info("Committing transaction"); transaction.Commit(); } } } }
//public object Get(Details details) //{ // Models.Recording recording = _recordingRepository.GetById(details.Id); // if (recording.Restricted && !UserSession.IsAuthenticated) // return HttpResult.Redirect("/Login".AddQueryParam("redirect", Request.AbsoluteUri)); // return new DetailsResponse {Recording = recording}; //} //public object Get(Delete delete) //{ // Models.Recording recording = _recordingRepository.GetById(delete.Id); // if (recording.Restricted && !UserSession.IsAuthenticated) return HttpResult.Redirect("/Login".AddQueryParam("redirect", Request.AbsoluteUri)); // return new DeleteResponse {Recording = recording}; //} //[Authenticate] //[RequiredRole(RoleNames.Admin)] //public object Post(Delete delete) //{ // _recordingRepository.Delete(delete.Id); // return this.Redirect("/Recording"); //} public object Get(SpeakerDetails speaker) { if (speaker.EscapedFragment == null && !Request.RawUrl.IsNormalizedUrl()) { return(this.RedirectPermanently(Request.RawUrl.ToNormalizedUrl())); } if (speaker.EscapedFragment != null && speaker.EscapedFragment.StartsWith("/")) { speaker.Album = speaker.EscapedFragment.Substring(1); } var includeRestricted = UserSession.IsAuthenticated; NameInfo nameInfo = speaker.Name.ToNameInfo(); using (IDbConnection db = _dbConnectionFactory.Open()) { DbSpeaker dbSpeaker = db.Single <DbSpeaker>(s => s.FirstName == nameInfo.FirstName && s.LastName == nameInfo.LastName && !s.Deleted); if (dbSpeaker == null) { throw HttpError.NotFound("Speaker not found"); } SqlExpression <DbRecording> albumIdQuery = db.From <DbRecording>() .Join <DbRecordingSpeaker>((recording, recordingSpeaker) => recording.Id == recordingSpeaker.RecordingId) .Where <DbRecording, DbRecordingSpeaker>((recording, recordingSpeaker) => !recording.Deleted && recordingSpeaker.SpeakerId == dbSpeaker.Id) .SelectDistinct(rs => rs.AlbumId); SqlExpression <DbSpeaker> query = db.From <DbSpeaker>() .Join <DbRecordingSpeaker>((sp, recordingSpeaker) => sp.Id == recordingSpeaker.SpeakerId) .Join <DbRecordingSpeaker, DbRecording>((recordingSpeaker, recording) => recordingSpeaker.RecordingId == recording.Id) .Join <DbRecording, DbAlbum>((recording, album) => recording.AlbumId == album.Id) .Where <DbSpeaker, DbAlbum>((sp, album) => !sp.Deleted && !album.Deleted && Sql.In(album.Id, albumIdQuery)) .OrderBy <DbAlbum>(a => a.Name) .ThenBy <DbRecording>(r => r.Track); if (!includeRestricted) { query.And <DbAlbum>(a => !a.Restricted); } List <Tuple <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum> > recordings = db.SelectMulti <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum>(query); Dictionary <long, DbAlbum> albums = recordings.DistinctBy(r => r.Item4.Id).Select(r => r.Item4).ToDictionary(a => a.Id); ILookup <long, Tuple <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum> > albumLookup = recordings.ToLookup(r => r.Item4.Id); ILookup <long, Tuple <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum> > speakers = recordings.ToLookup(r => r.Item3.Id); List <AlbumInfo> albumInfos = (from g in albumLookup let album = albums[g.Key] select new AlbumInfo { Uid = album.Uid, Name = album.Name, Description = album.Description, AlbumSpeakers = GetSpeakers(g), HasAlbumArt = album.AlbumArtPath != null, Recordings = g.DistinctBy(r => r.Item3.Id) .OrderBy(r => r.Item3.Track) .Select(r => new RecordingInfo { Uid = r.Item3.Uid, Title = r.Item3.Title, Track = r.Item3.Track, Year = r.Item3.Year, Comment = r.Item3.Comment, Speakers = speakers[r.Item3.Id] .DistinctBy(rs => rs.Item1.Id) .Select(rs => rs.Item1.ToSpeakerInfo()) .ToList() }).ToList(), Attachments = album.AttachmentPaths .Select((attachment, index) => new AttachmentInfo { Name = _fileSystem.Path.GetFileName(attachment), Index = index }).ToList() }).ToList(); return(new SpeakerDetailsResponse { Uid = dbSpeaker.Uid, Speaker = speaker.Name, Albums = albumInfos.ToList(), Speakers = _recordingRepository.GetSpeakers(includeRestricted).Select(s => s.ToSpeakerInfo(sp => sp.FullName == speaker.Name)).ToList(), SelectedAlbum = albumInfos.FirstOrDefault(a => a.Name == (speaker.Album ?? speaker.EscapedFragment)), HasPhoto = dbSpeaker.PhotoPath != null, Description = dbSpeaker.Description }); } }
public object Any(SpeakerFeedRequest speakerFeedRequest) { bool includeRestricted = UserSession.IsAuthenticated; const int limit = 50; XNamespace itunes = "http://www.itunes.com/dtds/podcast-1.0.dtd"; XNamespace atom = "http://www.w3.org/2005/Atom"; string siteUrl = Request.GetApplicationUrl(); string logoUrl = $"{siteUrl}/content/images/podcast_logo.png"; const string subscribe = @"<h4>Abonner i iTunes</h4> <ol> <li>Start iTunes</li> <li>Klikk Fil - Abonner på podcast (File - Subscribe to Podcast). (Trykk Alt-F for å få frem menyen i Windows.) <li>Lim inn lenken til denne siden, og klikk OK</li> </ol>"; using (IDbConnection db = _dbConnectionFactory.Open()) { DbSpeaker speaker = null; if (speakerFeedRequest.Speaker != null) { NameInfo nameInfo = speakerFeedRequest.Speaker?.ToNameInfo(); speaker = db.Single <DbSpeaker>(s => s.FirstName == nameInfo.FirstName && s.LastName == nameInfo.LastName && !s.Deleted); } string description = string.Empty; SqlExpression <DbSpeaker> query = db.From <DbSpeaker>() .Join <DbRecordingSpeaker>((sp, recordingSpeaker) => sp.Id == recordingSpeaker.SpeakerId) .Join <DbRecordingSpeaker, DbRecording>((recordingSpeaker, recording) => recordingSpeaker.RecordingId == recording.Id) .Join <DbRecording, DbAlbum>((recording, album) => recording.AlbumId == album.Id) .Where <DbRecording, DbSpeaker>((recording, sp) => !recording.Deleted && !sp.Deleted) .Take(limit); if (speaker != null) { query.And <DbSpeaker>(s => s.Id == speaker.Id); } else { query.OrderByDescending <DbRecording>(r => r.CreatedOn); } if (!includeRestricted) { query.And <DbRecording>(r => r.Restricted == false); } List <Tuple <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum> > speakerInfo = db.SelectMulti <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum>(query); ILookup <long, Tuple <DbSpeaker, DbRecordingSpeaker, DbRecording, DbAlbum> > recordingLookup = speakerInfo.ToLookup(s => s.Item3.Id); Dictionary <long, DbAlbum> albums = speakerInfo.DistinctBy(r => r.Item4.Id).Select(r => r.Item4).ToDictionary(a => a.Id); IEnumerable <XElement> items = from recording in speakerInfo.DistinctBy(r => r.Item3.Id).Select(r => r.Item3.ToRecording()) let album = albums[recording.AlbumId] let speakerName = recordingLookup[recording.Id] .Select(s => s.Item1).DistinctBy(s => s.Id) .Select(s => s.ToSpeaker().FullName) .ToSeparatedString('/') let trackDescription = $"{recording.Comment}{(recording.Year != null ? " ({0})".Fmt(recording.Year) : string.Empty)}".PadRight(1, '-') let tagInfo = GetTag(recording) let fileInfo = _fileSystem.FileInfo.FromFileName(recording.Path) let titleSuffix = tagInfo.Tag.TrackCount > 1 ? " ({0}/{1})".Fmt(tagInfo.Tag.Track, tagInfo.Tag.TrackCount) : string.Empty let url = $"{siteUrl}/Recording/Stream/{recording.Uid:N}/{fileInfo.Name.UrlEncode20()}" let guid = $"{siteUrl}/Recording/Stream/{recording.Uid:N}{(speakerFeedRequest.Speaker == null ? "/top50" : string.Empty)}" select new XElement("item", new XElement("title", $"{album.Name}: {recording.Title}{titleSuffix}" ), new XElement(itunes + "author", speakerName ), new XElement(itunes + "subtitle", $"{(speakerFeedRequest.Speaker == null ? $"{speakerName}: " : string.Empty)}{album.Name}" ), new XElement(itunes + "summary", new XCData(trackDescription) ), new XElement("description", $"{trackDescription}{Environment.NewLine}{subscribe}" ), new XElement(itunes + "image", new XAttribute("href", logoUrl) ), new XElement("enclosure", new XAttribute("url", url), new XAttribute("length", fileInfo.Length), new XAttribute("type", "audio/mpeg") ), new XElement("guid", guid ), new XElement("pubDate", recording.CreatedOn.ToString("r") ), new XElement(itunes + "duration", tagInfo.Properties.Duration.ToString(@"hh\:mm\:ss") ), new XElement(itunes + "explicit", "no" ) ); string title = speakerFeedRequest.Speaker ?? $"Siste {limit}"; string link = speakerFeedRequest.Speaker != null ? $"{siteUrl}/Recording/Speaker/{speakerFeedRequest.Speaker.UrlEncode20()}" : siteUrl; string selfUrl = $"{siteUrl}{Request.RawUrl}"; List <XElement> categories = new List <XElement>(); for (int i = 0; i < Configuration.PodcastCategories.Count; i++) { categories.Add(new XElement(itunes + "category", new XAttribute("text", Configuration.PodcastCategories[i]), new XElement(itunes + "category", new XAttribute("text", Configuration.PodcastSubcategories[i]) ) )); } XElement element = new XElement("rss", new XAttribute(XNamespace.Xmlns + "itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd"), new XAttribute(XNamespace.Xmlns + "atom", "http://www.w3.org/2005/Atom"), new XAttribute("version", "2.0"), new XElement("channel", new XElement(atom + "link", new XAttribute("href", selfUrl), new XAttribute("rel", "self"), new XAttribute("type", "application/rss+xml"), new XAttribute(XNamespace.Xmlns + "atom", atom) ), new XElement("title", $"{Configuration.SiteName}: {title}" ), new XElement("link", link ), new XElement("language", "no" ), new XElement("copyright", Configuration.CompanyName ), new XElement(itunes + "subtitle", Configuration.Slogan, new XAttribute(XNamespace.Xmlns + "itunes", itunes) ), new XElement(itunes + "author", speakerFeedRequest.Speaker ?? Configuration.CompanyName ), new XElement(itunes + "summary", new XCData(WebUtility.HtmlDecode(Configuration.MetaDescription)) ), new XElement("description", description ), new XElement(itunes + "owner", new XElement(itunes + "name", Configuration.CompanyName ), new XElement(itunes + "email", Configuration.CompanyEmail ) ), new XElement(itunes + "image", new XAttribute("href", logoUrl) ), categories, new XElement(itunes + "explicit", "no" ), items ) ); string podcastFeed = $@"<?xml version=""1.0"" encoding=""UTF-8""?>{Environment.NewLine}{element}"; return(new HttpResult(podcastFeed, "application/rss+xml")); } }