namespace Tesses.YouTubeDownloader.Droid; using Tesses.YouTubeDownloader; using Tesses.YouTubeDownloader.Server; using Tesses.WebServer; using Tesses.WebServer.Swagme; using Android.Content; using Android.Net; using Android.Database; using Android.OS; using Tesses.YouTubeDownloader.SFTP; using Renci.SshNet; using System.Net; using Android.Preferences; using AndroidX.Preference; using Android.Runtime; using Java.Interop; public class TYTDPreferences : PreferenceDataStore { public override bool GetBoolean(string? key, bool defValue) { if(key == TYTDCommon.TYTD_SERVER_ACCESSABLE) { return TYTDCommon.ServerAccessable; } if(key == TYTDCommon.TYTD_NO_EXTERNAL_INFO_THUMB) { //no scanning server for info or thumb return TYTDCommon.NoExtenalInfoThumbnail; } if(key == TYTDCommon.TYTD_CACHE_THUMBNAILS_ON_START) { return TYTDCommon.CacheThumbnailsFromServersOnStartup; } if(key == TYTDCommon.TYTD_CACHE_INFO_ON_START) { return TYTDCommon.CacheInfoFromServersOnStartup; } if(key == TYTDCommon.TYTD_CACHE_LAZY) { return TYTDCommon.CacheLazy; } if(key == TYTDCommon.TYTD_FETCH_THUMB_YOUTUBE) { return TYTDCommon.FetchThumbYouTube; } return defValue; } public override float GetFloat(string? key, float defValue) { return defValue; } public override int GetInt(string? key, int defValue) { if(key == TYTDCommon.TYTD_SERVER_PORT) { return TYTDCommon.ServerPort; } return defValue; } public override long GetLong(string? key, long defValue) { return defValue; } public override string? GetString(string? key, string? defValue) { if(key == TYTDCommon.TYTD_SERVER_PORT) { return TYTDCommon.ServerPort.ToString(); } if(key == TYTDCommon.TYTD_TAG) { return TYTDCommon.Tag; } return defValue; } public override ICollection? GetStringSet(string? key, ICollection? defValues) { return defValues; } public override void PutBoolean(string? key, bool value) { if(key == TYTDCommon.TYTD_SERVER_ACCESSABLE) { TYTDCommon.ServerAccessable=value; } if(key == TYTDCommon.TYTD_NO_EXTERNAL_INFO_THUMB) { //no scanning server for info or thumb TYTDCommon.NoExtenalInfoThumbnail = value; } if(key == TYTDCommon.TYTD_CACHE_THUMBNAILS_ON_START) { TYTDCommon.CacheThumbnailsFromServersOnStartup=value; } if(key == TYTDCommon.TYTD_CACHE_INFO_ON_START) { TYTDCommon.CacheInfoFromServersOnStartup=value; } if(key == TYTDCommon.TYTD_CACHE_LAZY) { TYTDCommon.CacheLazy=value; } if(key == TYTDCommon.TYTD_FETCH_THUMB_YOUTUBE) { TYTDCommon.FetchThumbYouTube=value; } } public override void PutFloat(string? key, float value) { } public override void PutInt(string? key, int value) { if(key == TYTDCommon.TYTD_SERVER_PORT) { if(value <= ushort.MaxValue) { TYTDCommon.ServerPort=(ushort)value; } } } public override void PutLong(string? key, long value) { base.PutLong(key, value); } public override void PutString(string? key, string? value) { if(key == TYTDCommon.TYTD_SERVER_PORT) { ushort value2; if(ushort.TryParse(value,out value2)) { TYTDCommon.ServerPort=value2; } } if(key == TYTDCommon.TYTD_TAG) { if(!string.IsNullOrWhiteSpace(value)){ TYTDCommon.Tag = value; }else{ TYTDCommon.Tag="UnknownPC"; } } } public override void PutStringSet(string? key, ICollection? values) { } } public static class CastExtensions { public static async Task CopyThumbnailsFromYouTubeAsync(this IStorage storage,string id) { if(id.Length == 11) { storage.CreateDirectoryIfNotExist($"Thumbnails/{id}"); await storage.CopyThumbnailFromYouTubeAsync(id,"default"); await storage.CopyThumbnailFromYouTubeAsync(id,"hqdefault"); await storage.CopyThumbnailFromYouTubeAsync(id,"maxresdefault"); await storage.CopyThumbnailFromYouTubeAsync(id,"mqdefault"); await storage.CopyThumbnailFromYouTubeAsync(id,"sddefault"); } } private static async Task CopyThumbnailFromYouTubeAsync(this IStorage storage,string id,string thumbnail) { string name=$"Thumbnails/{id}/{thumbnail}.jpg"; if(!storage.FileExists(name)) { try{ using(var src=await storage.HttpClient.GetStreamAsync($"https://i.ytimg.com/vi/{id}/{thumbnail}.jpg")){ using(var dest=await storage.CreateAsync(name)) { await src.CopyToAsync(dest); } }}catch(Exception ex) { _=ex; } } } private static async Task CopyThumbnailAsync(this ITYTDBase baseCtl,string id,string thumbnail,IStorage storage) { string name=$"Thumbnails/{id}/{thumbnail}.jpg"; if(!storage.FileExists(name) && baseCtl.FileExists(name)) { using(var src=await baseCtl.OpenReadAsync(name)){ using(var dest=await storage.CreateAsync(name)) { await src.CopyToAsync(dest); } } } } public static async Task CopyThumbnailsAsync(this ITYTDBase baseCtl,string id,IStorage storage) { storage.CreateDirectoryIfNotExist($"Thumbnails/{id}"); await baseCtl.CopyThumbnailAsync(id,"default",storage); await baseCtl.CopyThumbnailAsync(id,"hqdefault",storage); await baseCtl.CopyThumbnailAsync(id,"maxresdefault",storage); await baseCtl.CopyThumbnailAsync(id,"mqdefault",storage); await baseCtl.CopyThumbnailAsync(id,"sddefault",storage); await baseCtl.CopyThumbnailAsync(id,"900x900",storage); } public static async Task CastIfAsync(this T1? src,Func cb) where T2 : class { var type = src as T2; if(type != null && cb != null) { await cb(type); } } public static void CastIf(this T1? src,Action cb) where T2 : class { var type = src as T2; if(type != null && cb != null) { cb(type); } } } public static class TYTDCommon { #region PREFENCES public static string Tag { get{ if(ctx==null) return "UnknownPC"; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetString(TYTD_TAG,"UnknownPC"); if(!string.IsNullOrWhiteSpace(res2)) { return res2; } } return ""; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutString(TYTD_TAG,value); if(res2.Commit()) { Restart(); } } } } } public static bool ServerAccessable { get{ if(ctx==null) return false; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetBoolean(TYTD_SERVER_ACCESSABLE,false); return res2; } return false; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutBoolean(TYTD_SERVER_ACCESSABLE,value); if(res2.Commit()) { Restart(); } } } } } public static bool CacheLazy { get{ if(ctx==null) return false; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetBoolean(TYTD_CACHE_LAZY,false); return res2; } return false; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutBoolean(TYTD_CACHE_LAZY,value); res2.Apply(); } } } } public static bool CacheThumbnailsFromServersOnStartup { get{ if(ctx==null) return false; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetBoolean(TYTD_CACHE_THUMBNAILS_ON_START,false); return res2; } return false; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutBoolean(TYTD_CACHE_THUMBNAILS_ON_START,value); res2.Apply(); } } } } public static bool CacheInfoFromServersOnStartup { get{ if(ctx==null) return false; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetBoolean(TYTD_CACHE_INFO_ON_START,false); return res2; } return false; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutBoolean(TYTD_CACHE_INFO_ON_START,value); res2.Apply(); } } } } public static bool NoExtenalInfoThumbnail { get{ if(ctx==null) return false; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetBoolean(TYTD_NO_EXTERNAL_INFO_THUMB,false); return res2; } return false; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutBoolean(TYTD_NO_EXTERNAL_INFO_THUMB,value); res2.Apply(); } } } } public static bool FetchThumbYouTube { get{ if(ctx==null) return false; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetBoolean(TYTD_FETCH_THUMB_YOUTUBE,false); return res2; } return false; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutBoolean(TYTD_FETCH_THUMB_YOUTUBE,value); res2.Apply(); } } } } public static ushort ServerPort { get{ if(ctx==null) return 3252; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetInt(TYTD_SERVER_PORT,3252); if(res2 < 1025 || res2 > ushort.MaxValue) return 1025; return (ushort)res2; } return 3252; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutInt(TYTD_SERVER_PORT,value); if(res2.Commit()) { Restart(); } } } } } public static string AppDownloadLocation { get{ if(ctx==null) return ""; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetString(TYTD_DOWNLOAD_LOCATION,""); if(!string.IsNullOrWhiteSpace(res2)) { return res2; } } return ""; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutString(TYTD_DOWNLOAD_LOCATION,value); if(res2.Commit()) { Restart(); } } } } } public static string AppStorageLocation { get{ if(ctx==null) return ""; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.GetString(TYTD_STORE_LOCATION,""); if(!string.IsNullOrWhiteSpace(res2)) { return res2; } } return ""; } set{ if(ctx==null) return; var res=ctx.GetSharedPreferences(TYTD_CONFIG,FileCreationMode.Private); if(res != null) { var res2=res.Edit(); if(res2 != null) { res2.PutString(TYTD_STORE_LOCATION,value); if(res2.Commit()) { Restart(); } } } } } #endregion #region CONSTANTS public const string TYTD_CONFIG="tytdConfig"; public const string TYTD_TAG = "tytdTag"; public const string TYTD_STORE_LOCATION = "tytdStorageLocation"; public const string TYTD_DOWNLOAD_LOCATION = "tytdDownloadLocation"; public const string TYTD_SERVER_ACCESSABLE = "tytdServerAccessable"; public const string TYTD_SERVER_PORT= "tytdServerPort"; public const string TYTD_NO_EXTERNAL_INFO_THUMB= "tytdNoExternalInfoThumb"; public const string TYTD_CACHE_THUMBNAILS_ON_START="tytdCacheThumbnailsOnStart"; public const string TYTD_CACHE_INFO_ON_START = "tytdCacheInfoOnStart"; public const string TYTD_FETCH_THUMB_YOUTUBE = "tytdFetchThumbYouTube"; public const string TYTD_CACHE_LAZY="tytdCacheLazy"; #endregion #region PRIVATE_FIELDS private static string data_dir_internal=""; private static CancellationTokenSource? src=null; private static Context? ctx=null; private static CancellationToken token=default(CancellationToken); private static string server_url_file=""; private static List privateKeys=new List(); private static Dictionary svrs=new Dictionary(); #endregion #region PUBLIC_PROPERTIES public static Type? MainActivity {get;set;} public static Type? SettingsActivity {get;set;} public static ITYTDBase? TYTD {get;private set;} public static Context? Context {get{return ctx;}} public static ITYTDBase? LocalStorage {get;private set;} public static bool HasContext {get{return ctx != null;}} #endregion #region PUBLIC_METHODS public static Dictionary GetServers() { Dictionary servers=new Dictionary(); if(File.Exists(server_url_file)){ var lines=File.ReadAllLines(server_url_file); foreach(var line in lines) { string[] item=line.Split(':',2,StringSplitOptions.RemoveEmptyEntries); if(item.Length ==2) { servers.Add(item[0],item[1]); } } } return servers; } public static void SaveServers(Dictionary servers) { List servers_list=new List(); foreach(var svr in servers) { servers_list.Add($"{svr.Key.Replace(":","").Replace("\n","").Replace("\r","")}:{svr.Value.Replace("\n","").Replace("\r","")}"); } File.WriteAllLines(server_url_file,servers_list); } public static async Task GetBestThumbnailArrayAsync(string id,string thumbRes) { string thumb = $"Thumbnails/{id}/{thumbRes}.jpg"; if(LocalStorage!= null && LocalStorage.FileExists(thumb)) return await LocalStorage.ReadAllBytesAsync(thumb); if(TYTD != null && TYTD.FileExists(thumb)) { var bytes=await TYTD.ReadAllBytesAsync(thumb); if(CacheLazy && LocalStorage != null) { await LocalStorage.CastIfAsync(async(e)=>{ using(var f = await e.CreateAsync(thumb)) { await f.WriteAsync(bytes,0,bytes.Length); } }); } return bytes; } return Convert.FromBase64String("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"); } public static byte[] GetBestThumbnailArray(string id,string thumbRes) { return GetBestThumbnailArrayAsync(id,thumbRes).Result; } public static async IAsyncEnumerable EnumerateVideos() { if(NoExtenalInfoThumbnail) { if(LocalStorage == null) yield break; await foreach(var item in LocalStorage.GetVideosAsync()) { if(FetchThumbYouTube) { await LocalStorage.CastIfAsync(async(e)=>{ await e.CopyThumbnailsFromYouTubeAsync(item.Id); }); } yield return await Task.FromResult(item); } }else{ if(TYTD != null){ await foreach(var item in TYTD.GetVideosAsync()) { if(CacheLazy && LocalStorage != null && !LocalStorage.VideoInfoExists(item.Id)) { await LocalStorage.CastIfAsync(async(e)=>{ await e.WriteVideoInfoAsync(item); }); } yield return await Task.FromResult(item); } }else{ if(LocalStorage == null) yield break; await foreach(var item in LocalStorage.GetVideosAsync()) { if(FetchThumbYouTube || CacheLazy) { await LocalStorage.CastIfAsync(async(e)=>{ await e.CopyThumbnailsFromYouTubeAsync(item.Id); }); } yield return await Task.FromResult(item); } } } } public static void StartBootCache(Func startCacheCb,Action stopCacheCb) { if(CacheThumbnailsFromServersOnStartup || CacheInfoFromServersOnStartup) { T t = startCacheCb(); Thread thd=new Thread(async()=>{ if(LocalStorage != null ){ foreach(var server in GetServers()) { try{ var tytddb = getTYTDBase(server.Value,Path.Combine(data_dir_internal,"working"),privateKeys); await foreach(var item in tytddb.GetVideoIdsAsync()) { if(!LocalStorage.VideoInfoExists(item) && CacheInfoFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await e.WriteVideoInfoAsync(await tytddb.GetVideoInfoAsync(item)); }); } if(CacheThumbnailsFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await tytddb.CopyThumbnailsAsync(item,e); }); } } await foreach(var item in tytddb.GetPlaylistIdsAsync()) { if(!LocalStorage.PlaylistInfoExists(item) && CacheInfoFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await e.WritePlaylistInfoAsync(await tytddb.GetPlaylistInfoAsync(item)); }); } if(LocalStorage.PlaylistInfoExists(item)) { var pl=await LocalStorage.GetPlaylistInfoAsync(item); foreach(var id in pl.Videos) { if(!LocalStorage.VideoInfoExists(id) && tytddb.VideoInfoExists(id) && CacheInfoFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await e.WriteVideoInfoAsync(await tytddb.GetVideoInfoAsync(id)); }); } if(CacheThumbnailsFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await tytddb.CopyThumbnailsAsync(id,e); }); } } } } await foreach(var channel in tytddb.GetChannelIdsAsync()) { if(!LocalStorage.ChannelInfoExists(channel) && CacheInfoFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await e.WriteChannelInfoAsync(await tytddb.GetChannelInfoAsync(channel)); }); } if(CacheThumbnailsFromServersOnStartup) { await LocalStorage.CastIfAsync(async (e)=>{ await tytddb.CopyThumbnailsAsync(channel,e); }); } } }catch(Exception ex) { _=ex; } } } stopCacheCb(t); }); thd.Start(); } } public static List<(string Label,string Path)> GetStorageDevices() { List<(string Label,string Path)> paths=new List<(string Label, string Path)>(); if(ctx != null){ var dirs=ctx.GetExternalFilesDirs(null); if(dirs != null) foreach(var item in dirs) { string path=item.ToString(); if(path.StartsWith("/storage/emulated/")) { paths.Add(("Internal Storage",path)); }else{ if(path.StartsWith("/storage/")) { string[] path0=path.Split('/',3,StringSplitOptions.RemoveEmptyEntries); if(path0.Length >= 2) { paths.Add((path0[1],path)); }else{ paths.Add((path,path)); } }else{ paths.Add((path,path)); } } } } return paths; } public static void Close() { if(src != null) { src.Cancel(); src=null; } } public static void Restart() { if(ctx != null) reInit(ctx); } public static void Init(Android.Content.Context ctx) { if(!HasContext) { reInit(ctx); } } #endregion #region PRIVATE_METHODS private static void reInit(Android.Content.Context ctx) { Close(); src=new CancellationTokenSource(); var dir=ctx.GetExternalFilesDir(null); var token = src.Token; if(dir == null) return; TYTDCommon.ctx=ctx; TYTDCommon.token = token; data_dir_internal=dir.ToString(); server_url_file = Path.Combine(data_dir_internal,"servers.txt"); string applocationInternal = Path.Combine(data_dir_internal, "working"); string privKeyDir = Path.Combine(data_dir_internal,"privkeys"); Directory.CreateDirectory(privKeyDir); foreach(var priv in Directory.GetFiles(privKeyDir)) { privateKeys.Add(new PrivateKeyFile(priv)); } Directory.CreateDirectory(applocationInternal); System.Environment.CurrentDirectory = applocationInternal; string appStorageLocation = AppStorageLocation; string appDownloadLocation = AppDownloadLocation; TYTDStorage.SetTYTDTag(Tag); MountableServer svr=new MountableServer(new StaticServer(Path.Combine(data_dir_internal,"site"))); svr.Mount("/serveradmin/",getServerApi(data_dir_internal)); LocalStorage=getTYTDBase("",applocationInternal,privateKeys); var storage=getTYTDBase(appStorageLocation,applocationInternal,privateKeys); var downloader = getTYTDBase(appDownloadLocation,applocationInternal,privateKeys); ITYTDBase baseCtl=storage; if(storage != downloader) { var proxy = new TYTDDownloaderStorageProxy(); proxy.Storage = storage; downloader.CastIf((dl)=>{ proxy.Downloader = dl; }); baseCtl=proxy; } TYTD=baseCtl; TYTDServer server=new TYTDServer(baseCtl); server.RootServer.Server = svr; var svrCtl = baseCtl as IStorage; if(svrCtl != null){ ExtensionLoader.Loader loader=new ExtensionLoader.Loader(svrCtl); loader.SetServer(server); } HttpServerListener listener = new HttpServerListener(new IPEndPoint(ServerAccessable ? IPAddress.Any : IPAddress.Loopback,ServerPort),server.InnerServer); listener.ListenAsync(token).Wait(0); SetupChannels(); Intent intent=new Intent(ctx,typeof(TYTDServerService)); ctx.StartForegroundService(intent); } private static void SetupChannels() { if (Build.VERSION.SdkInt < BuildVersionCodes.O || ctx == null) { // Notification channels are new in API 26 (and not a part of the // support library). There is no need to create a notification // channel on older versions of Android. return; } NotificationChannel serverChannel = new NotificationChannel(TYTDServerService.SERVER_CHANNEL_ID, "TYTD Server", NotificationImportance.Default); NotificationManager? manager = (NotificationManager?)ctx.GetSystemService(Context.NotificationService); if (manager != null) { manager.CreateNotificationChannel(serverChannel); } } private static IServer getServerApi(string appDir) { StaticServer ssvr=new StaticServer(Path.Combine(appDir,"adminpanel")); MountableServer svr=new MountableServer(ssvr); SwagmeServer swagme = new SwagmeServer(); svr.Mount("/api/",swagme); return svr; } private static ITYTDBase getTYTDBase(string url,string internalUrl,IEnumerable privKeys) { if(!string.IsNullOrWhiteSpace(url)){ if(url.StartsWith('/')) { //file if(svrs.ContainsKey(url)) return svrs[url]; var item=new TYTDPathDirectory(url); item.CreateDirectories(); item.StartLoop(token); svrs.Add(url,item); return item; }else{ System.Uri uri = new(url); if(uri.Scheme == "http" || uri.Scheme == "https") { if(svrs.ContainsKey(url)) return svrs[url]; var item = new TYTDClient(url); svrs.Add(url,item); return item; } if(uri.Scheme == "sftp") { //sftp //we need to get username password string username = "root"; string? password = null; string userInfo=uri.UserInfo; if(!string.IsNullOrWhiteSpace(userInfo)) { string[] userInfoSplit = userInfo.Split(':',2,StringSplitOptions.RemoveEmptyEntries); if(userInfoSplit.Length == 2) { //username:password username = userInfoSplit[0]; password = userInfoSplit[1]; }else if(userInfoSplit.Length == 1) { //username only username = userInfoSplit[0]; } } if(string.IsNullOrWhiteSpace(password)) { try{ var item= new SSHFS(url,username,privKeys.ToArray()); item.CreateDirectories(); item.StartLoop(token); svrs.Add(url,item); return item; }catch(Exception ex) { _=ex; } }else{ try{ var item= new SSHFS(url,username,password); item.CreateDirectories(); item.StartLoop(token); svrs.Add(url,item); return item; }catch(Exception ex) { _=ex; } } //SSHFS ssh=new SSHFS(url,); } } } if(svrs.ContainsKey(internalUrl)) return svrs[internalUrl]; var item2= new TYTDPathDirectory(internalUrl); item2.CreateDirectories(); item2.StartLoop(token); svrs.Add(internalUrl,item2); return item2; } #endregion }