feat(ads/seo/release): v1.2.0 with live Google Ads, isolated ad profile, ads.txt, and SEO/AEO/GEO optimization

This commit is contained in:
Yun Chan 2026-09-14 00:39:44 +09:00
parent a88aafa1e5
commit 0e568f1f0a
975 changed files with 130593 additions and 16783 deletions

View file

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.IO;
using Paca.Mobile.Core;
using Xunit;
namespace Paca.Tests.Core;
public class SmartCollectionPlaylistGateTests
{
[Fact]
public void Gate231_SmartCollectionEngine_Categorizes_Shorts_And_LongForm_Correctly()
{
var items = new List<MediaItemMetadata>
{
new("id-1", "YouTube Short Dance", "https://youtube.com/shorts/xyz", 45, 15_000_000, "mp4"),
new("id-2", "Full University Lecture", "https://university.edu/lecture.mp4", 3600, 800_000_000, "mp4")
};
var collections = SmartCollectionEngine.GroupIntoCollections(items);
Assert.True(collections.ContainsKey("Shorts & Reels"));
Assert.Contains(collections["Shorts & Reels"], i => i.Id == "id-1");
Assert.True(collections.ContainsKey("Long-form & Lectures"));
Assert.Contains(collections["Long-form & Lectures"], i => i.Id == "id-2");
}
[Fact]
public void Gate232_SmartCollectionEngine_Categorizes_Audio_And_Social()
{
var items = new List<MediaItemMetadata>
{
new("id-3", "Pop Song Audio", "https://music.com/song", 180, 5_000_000, "mp3"),
new("id-4", "Twitter Funny Clip", "https://twitter.com/i/status/123", 15, 2_000_000, "mp4")
};
var collections = SmartCollectionEngine.GroupIntoCollections(items);
Assert.True(collections.ContainsKey("Music & Podcasts"));
Assert.Contains(collections["Music & Podcasts"], i => i.Id == "id-3");
Assert.True(collections.ContainsKey("Social Clips"));
Assert.Contains(collections["Social Clips"], i => i.Id == "id-4");
}
[Fact]
public void Gate233_SmartCollectionEngine_M3uPlaylistGenerator_GeneratesValidM3u8()
{
var items = new List<MediaItemMetadata>
{
new("id-1", "Short Video", "https://example.com/video1.mp4", 60, 10_000_000, "mp4", LocalPath: @"C:\Downloads\video1.mp4"),
new("id-2", "Audio Track", "https://example.com/audio.mp3", 120, 4_000_000, "mp3", LocalPath: @"C:\Downloads\audio.mp3")
};
var m3uContent = SmartCollectionEngine.GenerateM3u8Playlist("My Smart Playlist", items);
Assert.StartsWith("#EXTM3U", m3uContent.Trim());
Assert.Contains("#PLAYLIST:My Smart Playlist", m3uContent);
Assert.Contains("#EXTINF:60,Short Video", m3uContent);
Assert.Contains(@"C:\Downloads\video1.mp4", m3uContent);
Assert.Contains("#EXTINF:120,Audio Track", m3uContent);
Assert.Contains(@"C:\Downloads\audio.mp3", m3uContent);
}
[Fact]
public void Gate234_SmartCollectionEngine_HandlesEmptyAndInvalidDurations()
{
var items = new List<MediaItemMetadata>
{
new("id-unknown", "Live Stream Chunk", "https://live.com/stream", -1, 10_000, "ts", LocalPath: @"C:\Downloads\live.ts")
};
var m3uContent = SmartCollectionEngine.GenerateM3u8Playlist("Live", items);
Assert.Contains("#EXTINF:-1,Live Stream Chunk", m3uContent);
Assert.Contains(@"C:\Downloads\live.ts", m3uContent);
// Empty list
var emptyM3u = SmartCollectionEngine.GenerateM3u8Playlist("Empty", Array.Empty<MediaItemMetadata>());
Assert.StartsWith("#EXTM3U", emptyM3u.Trim());
}
}