Compare commits
3
Commits
bc9985a6f0
...
eb86bc8f66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb86bc8f66 | ||
|
|
4e87daf2b2 | ||
|
|
15b484bdf8 |
BIN
Binary file not shown.
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><sqlb_project><db path="D:/NextCloud/C#/URLNotesGrabberCORE/URLNotesGrabberCORE/bin/Debug/net8.0/TL.db" readonly="0" foreign_keys="1" case_sensitive_like="0" temp_store="0" wal_autocheckpoint="1000" synchronous="2"/><attached/><window><main_tabs open="structure browser pragmas query" current="3"/></window><tab_structure><column_width id="0" width="300"/><column_width id="1" width="0"/><column_width id="2" width="100"/><column_width id="3" width="3571"/><column_width id="4" width="0"/><expanded_item id="0" parent="1"/><expanded_item id="1" parent="1"/><expanded_item id="2" parent="1"/><expanded_item id="3" parent="1"/></tab_structure><tab_browse><table title="Posts" custom_title="0" dock_id="4" table="4,5:mainPosts"/><dock_state state="000000ff00000000fd00000001000000020000077400000365fc0100000005fb000000160064006f0063006b00420072006f00770073006500310100000000000004a10000000000000000fb000000160064006f0063006b00420072006f00770073006500320100000000000004a10000000000000000fb000000160064006f0063006b00420072006f00770073006500330100000000000004a10000000000000000fb000000160064006f0063006b00420072006f00770073006500350100000000000005f40000000000000000fc0000000000000774000001eb00fffffffa000000000100000002fb000000160064006f0063006b00420072006f00770073006500340100000000ffffffff000001eb00fffffffb000000160064006f0063006b00420072006f00770073006500340000000000ffffffff0000000000000000000007740000000000000004000000040000000800000008fc00000000"/><default_encoding codec=""/><browse_table_settings><table schema="main" name="Blogs" show_row_id="0" encoding="" plot_x_axis="" unlock_view_pk="_rowid_" freeze_columns="0"><sort><column index="3" mode="1"/></sort><column_widths><column index="1" value="257"/><column index="2" value="95"/><column index="3" value="54"/><column index="4" value="156"/></column_widths><filter_values/><conditional_formats/><row_id_formats/><display_formats/><hidden_columns/><plot_y_axes/><global_filter/></table><table schema="main" name="Notes" show_row_id="0" encoding="" plot_x_axis="" unlock_view_pk="_rowid_" freeze_columns="0"><sort><column index="4" mode="1"/></sort><column_widths><column index="1" value="207"/><column index="2" value="151"/><column index="3" value="263"/><column index="4" value="127"/><column index="5" value="59"/><column index="6" value="300"/><column index="7" value="191"/></column_widths><filter_values/><conditional_formats/><row_id_formats/><display_formats/><hidden_columns/><plot_y_axes/><global_filter/></table><table schema="main" name="Posts" show_row_id="0" encoding="" plot_x_axis="" unlock_view_pk="_rowid_" freeze_columns="0"><sort><column index="5" mode="1"/></sort><column_widths><column index="1" value="247"/><column index="2" value="151"/><column index="3" value="206"/><column index="4" value="300"/><column index="5" value="110"/><column index="6" value="191"/><column index="7" value="267"/><column index="8" value="116"/><column index="9" value="300"/><column index="10" value="300"/><column index="11" value="119"/><column index="12" value="255"/><column index="13" value="300"/><column index="14" value="71"/><column index="15" value="300"/><column index="16" value="300"/><column index="17" value="59"/><column index="18" value="113"/><column index="19" value="151"/><column index="20" value="300"/><column index="21" value="148"/><column index="22" value="300"/><column index="23" value="300"/><column index="24" value="59"/></column_widths><filter_values><column index="7" value="=1"/><column index="4" value="<>1"/></filter_values><conditional_formats/><row_id_formats/><display_formats/><hidden_columns/><plot_y_axes/><global_filter/></table></browse_table_settings></tab_browse><tab_sql><sql name="SQL 1">UPDATE Posts
|
||||||
|
SET HasNotesGathered = 0
|
||||||
|
WHERE (BlogName, PostID) IN (
|
||||||
|
SELECT p.BlogName, p.PostID
|
||||||
|
FROM Posts p
|
||||||
|
WHERE p.HasNotesGathered = 1
|
||||||
|
AND P.notesGatheredDatetime < 1774294520
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM Notes n
|
||||||
|
WHERE n.PostID = p.PostID
|
||||||
|
AND n.RootBlogName = p.BlogName
|
||||||
|
--AND n.Type NOT IN ('reblog', 'reply')
|
||||||
|
)
|
||||||
|
ORDER BY P.PostDate ASC
|
||||||
|
--LIMIT 500
|
||||||
|
);</sql><sql name="SQL 2">select *
|
||||||
|
from Blogs
|
||||||
|
--update blogs set HasBeenOutput = 1
|
||||||
|
where HasBeenOutput = 0
|
||||||
|
AND
|
||||||
|
blogname in
|
||||||
|
(
|
||||||
|
'teaberrybee',
|
||||||
|
'reddevilgoddesstoo',
|
||||||
|
'waywardog13',
|
||||||
|
'wzjustbrowsing-blog',
|
||||||
|
'lewerta',
|
||||||
|
'nudenymph',
|
||||||
|
'caylachief'
|
||||||
|
|
||||||
|
)</sql><sql name="SQL 3*">select RootBlogName, PostID, NoteBlogName || '.tumblr.com' as NoteBlogName, DatetimeCrawled, TimeStamp, type, RootBlogName || '.tumblr.com/post/' || postid, datetime(timestamp, 'unixepoch')
|
||||||
|
from Notes
|
||||||
|
where --type like 'r%' and
|
||||||
|
DatetimeCrawled <> '2/12/26 12am'
|
||||||
|
order by DatetimeCrawled desc, TimeStamp desc</sql><sql name="SQL 5">SELECT distinct
|
||||||
|
blogs.*
|
||||||
|
, blogname || '.tumblr.com'
|
||||||
|
FROM
|
||||||
|
Blogs
|
||||||
|
inner JOIN
|
||||||
|
Notes on notes.noteBlogName = blogs.BlogName
|
||||||
|
WHERE
|
||||||
|
HasBeenOutput = 0 and type = 'reblog'
|
||||||
|
order by
|
||||||
|
Notes.Type desc,
|
||||||
|
DateAdded desc
|
||||||
|
LIMIT 500;</sql><current_tab id="2"/></tab_sql></sqlb_project>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,6 +13,7 @@ using Microsoft.Extensions.Diagnostics.Latency;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
namespace URLNotesGrabberCORE
|
namespace URLNotesGrabberCORE
|
||||||
{
|
{
|
||||||
@@ -68,6 +69,30 @@ namespace URLNotesGrabberCORE
|
|||||||
|
|
||||||
internal class DataAccess
|
internal class DataAccess
|
||||||
{
|
{
|
||||||
|
private static IConfiguration? _configuration;
|
||||||
|
private static HashSet<long>? _postIdsToExclude;
|
||||||
|
|
||||||
|
static DataAccess()
|
||||||
|
{
|
||||||
|
_configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.Build();
|
||||||
|
var excludeSetting = _configuration["appSettings:PostIDToExclude"];
|
||||||
|
if (!string.IsNullOrWhiteSpace(excludeSetting))
|
||||||
|
{
|
||||||
|
_postIdsToExclude = excludeSetting.Split(',')
|
||||||
|
.Select(s => long.TryParse(s.Trim(), out var id) ? id : (long?)null)
|
||||||
|
.Where(id => id.HasValue)
|
||||||
|
.Select(id => id.Value)
|
||||||
|
.ToHashSet();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_postIdsToExclude = new HashSet<long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string Q(string input)
|
public static string Q(string input)
|
||||||
{
|
{
|
||||||
return "'" + input.Replace("'", "''") + "'";
|
return "'" + input.Replace("'", "''") + "'";
|
||||||
@@ -124,6 +149,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
Console.WriteLine($"Error checking/creating replyText column: {ex.Message}");
|
Console.WriteLine($"Error checking/creating replyText column: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -132,8 +158,57 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EnsureBlogsLikesColumnsExist(string DBPath = @"TL.db")
|
||||||
|
{
|
||||||
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
string checkSql = "PRAGMA table_info(Blogs);";
|
||||||
|
bool likesPulledExists = false;
|
||||||
|
bool likesCursorExists = false;
|
||||||
|
|
||||||
|
using (SQLiteCommand command = new SQLiteCommand(checkSql, connection))
|
||||||
|
{
|
||||||
|
using (SQLiteDataReader reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
string columnName = reader.GetString(1);
|
||||||
|
if (columnName.Equals("LikesPulled", StringComparison.OrdinalIgnoreCase)) likesPulledExists = true;
|
||||||
|
if (columnName.Equals("LikesCursor", StringComparison.OrdinalIgnoreCase)) likesCursorExists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!likesPulledExists)
|
||||||
|
{
|
||||||
|
string addCol = "ALTER TABLE Blogs ADD COLUMN LikesPulled INTEGER DEFAULT 0;";
|
||||||
|
using (SQLiteCommand cmd = new SQLiteCommand(addCol, connection)) cmd.ExecuteNonQuery();
|
||||||
|
Console.WriteLine("[Migration] Added LikesPulled column to Blogs table");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!likesCursorExists)
|
||||||
|
{
|
||||||
|
string addCol = "ALTER TABLE Blogs ADD COLUMN LikesCursor INTEGER DEFAULT 0;";
|
||||||
|
using (SQLiteCommand cmd = new SQLiteCommand(addCol, connection)) cmd.ExecuteNonQuery();
|
||||||
|
Console.WriteLine("[Migration] Added LikesCursor column to Blogs table");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error mapping Blogs likes columns: {ex.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Adds
|
#region Adds
|
||||||
public static void AddBlog(string blogName, string DBPath = @"TL.db")
|
public static void AddBlog(string blogName, bool byLikes = false, string DBPath = @"TL.db")
|
||||||
{
|
{
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
|
||||||
@@ -145,17 +220,20 @@ namespace URLNotesGrabberCORE
|
|||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
// Insert BlogName and DateAdded (current UTC datetime)
|
// Insert BlogName and DateAdded (current UTC datetime)
|
||||||
string sql = "INSERT OR IGNORE INTO Blogs (BlogName, DateAdded) VALUES (@BlogName, @DateAdded)";
|
string sql = "INSERT OR IGNORE INTO Blogs (BlogName, DateAdded, DateModified, ByLikes) VALUES (@BlogName, @DateAdded, @DateModified, @ByLikes)";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@BlogName", blogName);
|
command.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
command.Parameters.AddWithValue("@DateAdded", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
command.Parameters.AddWithValue("@DateAdded", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
command.Parameters.AddWithValue("@DateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
command.Parameters.AddWithValue("@ByLikes", byLikes ? 1 : 0);
|
||||||
command.ExecuteNonQuery();
|
command.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
// Console.WriteLine("+ " + blogName);
|
// Console.WriteLine("+ " + blogName);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Blogs.BlogName")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Blogs.BlogName")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -165,11 +243,11 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddPost(string blogName, long postID, string reblogURL, string postDate, string postURL, string slug, string reblogKey, string reblogName, string summary, string quote, string body, string tags, string link, string photoURL, string photoCaption, string downloadedFiles, string audioCaption, string question, string answer, string title, bool hasImage, string DBPath = @"TL.db")
|
public static void AddPost(string blogName, long postID, string reblogURL, string postDate, string postURL, string slug, string reblogKey, string reblogName, string summary, string quote, string body, string tags, string link, string photoURL, string photoCaption, string downloadedFiles, string audioCaption, string question, string answer, string title, bool hasImage, bool byLikes = false, string DBPath = @"TL.db", string? rootBlogName = null, string? rootURL = null)
|
||||||
{
|
{
|
||||||
try { AddBlog(blogName, DBPath); } catch { }
|
try { AddBlog(blogName, byLikes, DBPath); } catch { }
|
||||||
try { UpdatePostSetDate(blogName, postID, postDate, DBPath); } catch { }
|
try { UpdatePostSetDate(blogName, postID, postDate, DBPath); } catch { }
|
||||||
try { UpdatePost(blogName, postID, reblogURL, postDate, postURL, slug, reblogKey, reblogName, summary, quote, body, tags, link, photoURL, photoCaption, downloadedFiles, audioCaption, question, answer, title, hasImage, DBPath); } catch { }
|
try { UpdatePost(blogName, postID, reblogURL, postDate, postURL, slug, reblogKey, reblogName, summary, quote, body, tags, link, photoURL, photoCaption, downloadedFiles, audioCaption, question, answer, title, hasImage, byLikes, DBPath, rootBlogName, rootURL); } catch { }
|
||||||
|
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
|
||||||
@@ -198,40 +276,67 @@ namespace URLNotesGrabberCORE
|
|||||||
Question,
|
Question,
|
||||||
Answer,
|
Answer,
|
||||||
Title,
|
Title,
|
||||||
HasImage
|
DateModified,
|
||||||
|
RootBlogName,
|
||||||
|
RootURL,
|
||||||
|
HasImage,
|
||||||
|
ByLikes
|
||||||
) VALUES (" +
|
) VALUES (" +
|
||||||
Q(blogName) + ", " + postID + ", " + Q(reblogURL) + ", " + Q(postDate) + ", " + Q(postURL) + ", " + Q(slug) + ", " + Q(reblogKey) + ", " + Q(reblogName) + ", " + Q(summary) + ", " + Q(quote) + ", " + Q(body) + ", " + Q(tags) + ", " + Q(link) + ", " + Q(photoURL) + ", " + Q(photoCaption) + ", " + Q(downloadedFiles) + ", " + Q(audioCaption) + ", " + Q(question) + ", " + Q(answer) + ", " + Q(title) + ", " + hasImage + ")";
|
Q(blogName) + ", " + postID + ", " + Q(reblogURL) + ", " + Q(postDate) + ", " + Q(postURL) + ", " + Q(slug) + ", " + Q(reblogKey) + ", " + Q(reblogName) + ", " + Q(summary) + ", " + Q(quote) + ", " + Q(body) + ", " + Q(tags) + ", " + Q(link) + ", " + Q(photoURL) + ", " + Q(photoCaption) + ", " + Q(downloadedFiles) + ", " + Q(audioCaption) + ", " + Q(question) + ", " + Q(answer) + ", " + Q(title) + ", " + Q(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) + ", " + Q(rootBlogName ?? ".") + ", " + Q(rootURL ?? ".") + ", " + (hasImage ? 1 : 0) + ", " + (byLikes ? 1 : 0) + ")";
|
||||||
SQLiteCommand command = new SQLiteCommand(sql, connection);
|
SQLiteCommand command = new SQLiteCommand(sql, connection);
|
||||||
|
|
||||||
command.ExecuteNonQuery();
|
int rowsInserted = 0;
|
||||||
}
|
try
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
rowsInserted = command.ExecuteNonQuery();
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Breakpoint here
|
||||||
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
///
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
string updateSql = "UPDATE Posts SET hasImage = " + hasImage + ", DateModified = '" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' WHERE blogName = '" + blogName + "' AND postID = '" + postID + "'";
|
||||||
|
SQLiteCommand updateCommand = new SQLiteCommand(updateSql, connection);
|
||||||
|
|
||||||
|
updateCommand.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
catch (Exception ex2)
|
||||||
|
{
|
||||||
|
// Breakpoint here
|
||||||
|
if (ex2.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex2.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
///
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update HasBeenOutput and DateAdded if a new post was inserted
|
||||||
|
if (rowsInserted == 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
///
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connection.Open();
|
string updateBlogSql = "UPDATE Blogs SET HasBeenOutput = 0, DateAdded = @DateAdded, DateModified = @DateModified WHERE BlogName = @BlogName";
|
||||||
|
using (var updateBlogCommand = new SQLiteCommand(updateBlogSql, connection))
|
||||||
string sql = "UPDATE Posts SET hasImage = " + hasImage + "WHERE blogName = '" + blogName + "' AND postID = '" + postID + "'";
|
|
||||||
SQLiteCommand command = new SQLiteCommand(sql, connection);
|
|
||||||
|
|
||||||
command.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
catch (Exception ex2)
|
|
||||||
{
|
|
||||||
if (ex2.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex2.Message);
|
updateBlogCommand.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
|
updateBlogCommand.Parameters.AddWithValue("@DateAdded", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
updateBlogCommand.Parameters.AddWithValue("@DateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
updateBlogCommand.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
catch { }
|
||||||
{
|
|
||||||
connection.Close();
|
|
||||||
}
|
|
||||||
///
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -240,7 +345,6 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void AddAPICount(string DBPath = @"TL.db")
|
public static void AddAPICount(string DBPath = @"TL.db")
|
||||||
{
|
{
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
@@ -260,6 +364,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
//Console.WriteLine(ex.Message);
|
//Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -271,18 +376,18 @@ namespace URLNotesGrabberCORE
|
|||||||
public static bool AddNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string DBPath = @"TL.db")
|
public static bool AddNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string DBPath = @"TL.db")
|
||||||
{
|
{
|
||||||
//try { AddPost(rootBlogName, postID, DBPath); } catch { }
|
//try { AddPost(rootBlogName, postID, DBPath); } catch { }
|
||||||
try { AddBlog(noteBlogName, DBPath); } catch { }
|
try { AddBlog(noteBlogName, false, DBPath); } catch { }
|
||||||
|
|
||||||
Console.WriteLine("{2}\t{0}\t{1}", UnixTimeStampToDateTime(timestamp), noteBlogName, type);
|
Console.WriteLine("{2}\t{0}\t{1}", UnixTimeStampToDateTime(timestamp), noteBlogName, type);
|
||||||
|
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection2 = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection2.Open();
|
||||||
|
|
||||||
string sql = "INSERT OR IGNORE INTO Notes (rootBlogName, noteBlogName, PostID, TimeStamp, Type, DatetimeCrawled) values(@rootBlogName, @noteBlogName, @PostID, @TimeStamp, @Type, @DatetimeCrawled)";
|
string sql = "INSERT OR IGNORE INTO Notes (rootBlogName, noteBlogName, PostID, TimeStamp, Type, DatetimeCrawled, DateModified) values(@rootBlogName, @noteBlogName, @PostID, @TimeStamp, @Type, @DatetimeCrawled, @DateModified)";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection2))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
||||||
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
|
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
|
||||||
@@ -290,12 +395,30 @@ namespace URLNotesGrabberCORE
|
|||||||
command.Parameters.AddWithValue("@TimeStamp", timestamp);
|
command.Parameters.AddWithValue("@TimeStamp", timestamp);
|
||||||
command.Parameters.AddWithValue("@Type", type ?? string.Empty);
|
command.Parameters.AddWithValue("@Type", type ?? string.Empty);
|
||||||
command.Parameters.AddWithValue("@DatetimeCrawled", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
command.Parameters.AddWithValue("@DatetimeCrawled", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
command.Parameters.AddWithValue("@DateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
|
||||||
command.ExecuteNonQuery();
|
int rowsInserted = command.ExecuteNonQuery();
|
||||||
|
|
||||||
|
// Only update HasBeenOutput if a new note was inserted
|
||||||
|
if (rowsInserted == 1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string updateSql = "UPDATE Blogs SET HasBeenOutput = 0, DateModified = @DateModified WHERE BlogName = @BlogName";
|
||||||
|
using (var updateCommand = new SQLiteCommand(updateSql, connection2))
|
||||||
|
{
|
||||||
|
updateCommand.Parameters.AddWithValue("@BlogName", noteBlogName);
|
||||||
|
updateCommand.Parameters.AddWithValue("@DateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
updateCommand.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName")
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
@@ -304,7 +427,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
connection.Close();
|
connection2.Close();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -330,7 +453,7 @@ namespace URLNotesGrabberCORE
|
|||||||
string sql = "SELECT " +
|
string sql = "SELECT " +
|
||||||
" MAX(Posts.BlogName) as BlogName, " + Environment.NewLine +
|
" MAX(Posts.BlogName) as BlogName, " + Environment.NewLine +
|
||||||
" Posts.PostID, " + Environment.NewLine +
|
" Posts.PostID, " + Environment.NewLine +
|
||||||
" 1925013599 as LatestNoteTimestamp, " + Environment.NewLine +
|
" 1925013599 as LatestNoteTimestamp, " + Environment.NewLine +
|
||||||
" Posts.NotesGatheredDatetime, " + Environment.NewLine +
|
" Posts.NotesGatheredDatetime, " + Environment.NewLine +
|
||||||
" CNT.CNT " + Environment.NewLine +
|
" CNT.CNT " + Environment.NewLine +
|
||||||
"FROM " + Environment.NewLine +
|
"FROM " + Environment.NewLine +
|
||||||
@@ -342,7 +465,10 @@ namespace URLNotesGrabberCORE
|
|||||||
"WHERE NotFound = 0 AND HasImage = 1 AND DownloadedFiles <> '.' " + Environment.NewLine;
|
"WHERE NotFound = 0 AND HasImage = 1 AND DownloadedFiles <> '.' " + Environment.NewLine;
|
||||||
|
|
||||||
if (withoutNotesOnly)
|
if (withoutNotesOnly)
|
||||||
|
{
|
||||||
sql += " and HasNotesGathered = 0 " + Environment.NewLine;
|
sql += " and HasNotesGathered = 0 " + Environment.NewLine;
|
||||||
|
sql += "OR ( Posts.blogname = 'zomb-eh' and [notesGatheredDateTime] < datetime('now', 'localtime', '-3 days') and ( ( postdate > '1/1/26' or ( HasNotesGathered = 1 and PostDate > '8/1/23' ) ) ) )" + Environment.NewLine;
|
||||||
|
}
|
||||||
|
|
||||||
// Filter by NotesGatheredDateTime if beforeDate is provided
|
// Filter by NotesGatheredDateTime if beforeDate is provided
|
||||||
if (beforeDate.HasValue)
|
if (beforeDate.HasValue)
|
||||||
@@ -356,9 +482,9 @@ namespace URLNotesGrabberCORE
|
|||||||
"ORDER BY " + Environment.NewLine +
|
"ORDER BY " + Environment.NewLine +
|
||||||
" notesgathereddatetime, Posts.PostDate desc, Posts.BlogName, Posts.PostID" + Environment.NewLine;
|
" notesgathereddatetime, Posts.PostDate desc, Posts.BlogName, Posts.PostID" + Environment.NewLine;
|
||||||
|
|
||||||
//Console.WriteLine(withoutNotesOnly);
|
Console.WriteLine(withoutNotesOnly);
|
||||||
//Console.WriteLine(sql);
|
Console.WriteLine(sql);
|
||||||
//Console.Write(">"); //Console.ReadKey();
|
Console.Write(">" ); //Console.ReadKey();
|
||||||
//Thread.Sleep(250);
|
//Thread.Sleep(250);
|
||||||
|
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
@@ -373,10 +499,58 @@ namespace URLNotesGrabberCORE
|
|||||||
long lastNoteTimestamp;
|
long lastNoteTimestamp;
|
||||||
long notesGatheredTimestamp;
|
long notesGatheredTimestamp;
|
||||||
|
|
||||||
blog = reader.GetString(0); // Assuming Title is the second column
|
// Diagnostic logging before each cast
|
||||||
postID = reader.GetInt64(1); // Assuming Id is the first column
|
//for (int i = 0; i < reader.FieldCount; i++)
|
||||||
lastNoteTimestamp = reader.GetInt64(2); // Assuming Id is the first column
|
//{
|
||||||
notesGatheredTimestamp = reader.GetInt64(3); // Assuming Id is the first column
|
// var value = reader.GetValue(i);
|
||||||
|
// var type = reader.GetFieldType(i);
|
||||||
|
// Console.WriteLine($"[GetPosts] Column {i}: Name={reader.GetName(i)}, Value={value}, Type={type}");
|
||||||
|
//}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
blog = Convert.ToString(reader.GetValue(0));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Breakpoint here
|
||||||
|
Console.WriteLine($"[GetPosts] Error casting column 0 to string: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
postID = Convert.ToInt64(reader.GetValue(1));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Breakpoint here
|
||||||
|
Console.WriteLine($"[GetPosts] Error casting column 1 to Int64: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lastNoteTimestamp = Convert.ToInt64(reader.GetValue(2));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Breakpoint here
|
||||||
|
Console.WriteLine($"[GetPosts] Error casting column 2 to Int64: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
notesGatheredTimestamp = Convert.ToInt64(reader.GetValue(3));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Breakpoint here
|
||||||
|
Console.WriteLine($"[GetPosts] Error casting column 3 to Int64: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude if postID is in the exclusion list
|
||||||
|
if (_postIdsToExclude != null && _postIdsToExclude.Contains(postID))
|
||||||
|
continue;
|
||||||
|
|
||||||
post = new Tuple<string, long, long, long>(blog, postID, lastNoteTimestamp, notesGatheredTimestamp);
|
post = new Tuple<string, long, long, long>(blog, postID, lastNoteTimestamp, notesGatheredTimestamp);
|
||||||
posts.Add(post);
|
posts.Add(post);
|
||||||
@@ -386,6 +560,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -428,6 +603,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -478,6 +654,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
Console.WriteLine($"Error getting replies with missing text: {ex.Message}");
|
Console.WriteLine($"Error getting replies with missing text: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -530,6 +707,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
Console.WriteLine($"Error getting replies with filled text: {ex.Message}");
|
Console.WriteLine($"Error getting replies with filled text: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -566,6 +744,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -576,6 +755,49 @@ namespace URLNotesGrabberCORE
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Tuple<string, int, long>> GetBlogsForLikes(string specificBlog = null, string DBPath = @"TL.db")
|
||||||
|
{
|
||||||
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
List<Tuple<string, int, long>> blogs = new List<Tuple<string, int, long>>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
string sql;
|
||||||
|
if (!string.IsNullOrEmpty(specificBlog))
|
||||||
|
sql = "SELECT BlogName, COALESCE(LikesPulled, 0), COALESCE(LikesCursor, 0) FROM Blogs WHERE BlogName = @blog";
|
||||||
|
else
|
||||||
|
sql = "SELECT BlogName, COALESCE(LikesPulled, 0), COALESCE(LikesCursor, 0) FROM Blogs WHERE COALESCE(LikesPulled, 0) = 0";
|
||||||
|
|
||||||
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(specificBlog))
|
||||||
|
command.Parameters.AddWithValue("@blog", specificBlog);
|
||||||
|
|
||||||
|
using (SQLiteDataReader reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
blogs.Add(new Tuple<string, int, long>(
|
||||||
|
reader.GetString(0),
|
||||||
|
reader.GetInt32(1),
|
||||||
|
reader.GetInt64(2)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error fetching blogs for likes: {ex.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
return blogs;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<string> GetBlogs(bool reblogsOnly, int from, int to, int top, string DBPath = @"TL.db")
|
public static List<string> GetBlogs(bool reblogsOnly, int from, int to, int top, string DBPath = @"TL.db")
|
||||||
{
|
{
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
@@ -609,6 +831,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -652,6 +875,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -675,10 +899,11 @@ namespace URLNotesGrabberCORE
|
|||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
//string sql = "UPDATE Posts SET HasNotesGathered = 1, NotesGatheredDateTime = @notesGathered WHERE BlogName = @BlogName AND PostID = @PostID";
|
//string sql = "UPDATE Posts SET HasNotesGathered = 1, NotesGatheredDateTime = @notesGathered WHERE BlogName = @BlogName AND PostID = @PostID";
|
||||||
string sql = "UPDATE Posts SET HasNotesGathered = 1, NotesGatheredDateTime = @notesGathered WHERE PostID = @PostID";
|
string sql = "UPDATE Posts SET HasNotesGathered = 1, NotesGatheredDateTime = @notesGathered, DateModified = @dateModified WHERE PostID = @PostID";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@notesGathered", DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
command.Parameters.AddWithValue("@notesGathered", DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.Parameters.AddWithValue("@BlogName", blogName);
|
command.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
command.Parameters.AddWithValue("@PostID", postID);
|
command.Parameters.AddWithValue("@PostID", postID);
|
||||||
command.ExecuteNonQuery();
|
command.ExecuteNonQuery();
|
||||||
@@ -686,6 +911,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -706,9 +932,10 @@ namespace URLNotesGrabberCORE
|
|||||||
|
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
string sql = "UPDATE Posts SET NotFound = 1 WHERE BlogName = @BlogName AND PostID = @PostID";
|
string sql = "UPDATE Posts SET NotFound = 1, DateModified = @dateModified WHERE BlogName = @BlogName AND PostID = @PostID";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.Parameters.AddWithValue("@BlogName", blogName);
|
command.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
command.Parameters.AddWithValue("@PostID", postID);
|
command.Parameters.AddWithValue("@PostID", postID);
|
||||||
command.ExecuteNonQuery();
|
command.ExecuteNonQuery();
|
||||||
@@ -716,6 +943,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -733,10 +961,11 @@ namespace URLNotesGrabberCORE
|
|||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
string sql = "UPDATE Posts SET postDate = @postDate WHERE BlogName = @BlogName AND PostID = @PostID";
|
string sql = "UPDATE Posts SET postDate = @postDate, DateModified = @dateModified WHERE BlogName = @BlogName AND PostID = @PostID";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@postDate", postDate ?? string.Empty);
|
command.Parameters.AddWithValue("@postDate", postDate ?? string.Empty);
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.Parameters.AddWithValue("@BlogName", blogName);
|
command.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
command.Parameters.AddWithValue("@PostID", postID);
|
command.Parameters.AddWithValue("@PostID", postID);
|
||||||
command.ExecuteNonQuery();
|
command.ExecuteNonQuery();
|
||||||
@@ -744,6 +973,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -756,7 +986,7 @@ namespace URLNotesGrabberCORE
|
|||||||
public static bool UpdateNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string DBPath = @"TL.db")
|
public static bool UpdateNote(string rootBlogName, string noteBlogName, long postID, long timestamp, string type, string DBPath = @"TL.db")
|
||||||
{
|
{
|
||||||
//try { AddPost(rootBlogName, postID, DBPath); } catch { }
|
//try { AddPost(rootBlogName, postID, DBPath); } catch { }
|
||||||
try { AddBlog(noteBlogName, DBPath); } catch { }
|
try { AddBlog(noteBlogName, false, DBPath); } catch { }
|
||||||
|
|
||||||
Console.WriteLine("{2}\t{0}\t{1}", UnixTimeStampToDateTime(timestamp), noteBlogName, type);
|
Console.WriteLine("{2}\t{0}\t{1}", UnixTimeStampToDateTime(timestamp), noteBlogName, type);
|
||||||
|
|
||||||
@@ -766,10 +996,11 @@ namespace URLNotesGrabberCORE
|
|||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
string sql = "UPDATE Notes SET timestamp = @timestamp WHERE rootBlogName = @rootBlogName AND noteBlogName = @noteBlogName AND PostID = @postID";
|
string sql = "UPDATE Notes SET timestamp = @timestamp, DateModified = @dateModified WHERE rootBlogName = @rootBlogName AND noteBlogName = @noteBlogName AND PostID = @postID";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@timestamp", timestamp);
|
command.Parameters.AddWithValue("@timestamp", timestamp);
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
||||||
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
|
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
|
||||||
command.Parameters.AddWithValue("@postID", postID);
|
command.Parameters.AddWithValue("@postID", postID);
|
||||||
@@ -778,6 +1009,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName")
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
@@ -792,7 +1024,7 @@ namespace URLNotesGrabberCORE
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdatePost(string blogName, long postID, string reblogURL, string postDate, string postURL, string slug, string reblogKey, string reblogName, string summary, string quote, string body, string tags, string link, string photoURL, string photoCaption, string downloadedFiles, string audioCaption, string question, string answer, string title, bool hasImage, string DBPath = @"TL.db")
|
public static void UpdatePost(string blogName, long postID, string reblogURL, string postDate, string postURL, string slug, string reblogKey, string reblogName, string summary, string quote, string body, string tags, string link, string photoURL, string photoCaption, string downloadedFiles, string audioCaption, string question, string answer, string title, bool hasImage, bool byLikes = false, string DBPath = @"TL.db", string? rootBlogName = null, string? rootURL = null)
|
||||||
{
|
{
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
|
||||||
@@ -819,7 +1051,11 @@ namespace URLNotesGrabberCORE
|
|||||||
sql += "question = @question, ";
|
sql += "question = @question, ";
|
||||||
sql += "answer = @answer, ";
|
sql += "answer = @answer, ";
|
||||||
sql += "title = @title, ";
|
sql += "title = @title, ";
|
||||||
sql += "hasImage = @hasImage ";
|
sql += "DateModified = @dateModified, ";
|
||||||
|
sql += "RootBlogName = CASE WHEN @rootBlogName IS NULL OR @rootBlogName = '' OR @rootBlogName = '.' THEN RootBlogName ELSE @rootBlogName END, ";
|
||||||
|
sql += "RootURL = CASE WHEN @rootURL IS NULL OR @rootURL = '' OR @rootURL = '.' THEN RootURL ELSE @rootURL END, ";
|
||||||
|
sql += "hasImage = @hasImage, ";
|
||||||
|
sql += "ByLikes = @byLikes ";
|
||||||
sql += " WHERE BlogName = @BlogName AND PostID = @PostID";
|
sql += " WHERE BlogName = @BlogName AND PostID = @PostID";
|
||||||
|
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
@@ -842,7 +1078,11 @@ namespace URLNotesGrabberCORE
|
|||||||
command.Parameters.AddWithValue("@question", question ?? string.Empty);
|
command.Parameters.AddWithValue("@question", question ?? string.Empty);
|
||||||
command.Parameters.AddWithValue("@answer", answer ?? string.Empty);
|
command.Parameters.AddWithValue("@answer", answer ?? string.Empty);
|
||||||
command.Parameters.AddWithValue("@title", title ?? string.Empty);
|
command.Parameters.AddWithValue("@title", title ?? string.Empty);
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
command.Parameters.AddWithValue("@rootBlogName", string.IsNullOrWhiteSpace(rootBlogName) ? (object)DBNull.Value : rootBlogName);
|
||||||
|
command.Parameters.AddWithValue("@rootURL", string.IsNullOrWhiteSpace(rootURL) ? (object)DBNull.Value : rootURL);
|
||||||
command.Parameters.AddWithValue("@hasImage", hasImage ? 1 : 0);
|
command.Parameters.AddWithValue("@hasImage", hasImage ? 1 : 0);
|
||||||
|
command.Parameters.AddWithValue("@byLikes", byLikes ? 1 : 0);
|
||||||
command.Parameters.AddWithValue("@BlogName", blogName);
|
command.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
command.Parameters.AddWithValue("@PostID", postID);
|
command.Parameters.AddWithValue("@PostID", postID);
|
||||||
|
|
||||||
@@ -852,6 +1092,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -869,15 +1110,17 @@ namespace URLNotesGrabberCORE
|
|||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
string sql = "UPDATE Blogs SET HasBeenOutput = 1 WHERE BlogName = @BlogName";
|
string sql = "UPDATE Blogs SET HasBeenOutput = 1, DateModified = @DateModified WHERE BlogName = @BlogName";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@BlogName", blogName);
|
command.Parameters.AddWithValue("@BlogName", blogName);
|
||||||
|
command.Parameters.AddWithValue("@DateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.ExecuteNonQuery();
|
command.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -887,6 +1130,32 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void UpdateBlogLikesStatus(string blogName, int likesPulled, long likesCursor, string DBPath = @"TL.db")
|
||||||
|
{
|
||||||
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
string sql = "UPDATE Blogs SET LikesPulled = @pulled, LikesCursor = @cursor, DateModified = @modified WHERE BlogName = @name";
|
||||||
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@pulled", likesPulled);
|
||||||
|
command.Parameters.AddWithValue("@cursor", likesCursor);
|
||||||
|
command.Parameters.AddWithValue("@modified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
command.Parameters.AddWithValue("@name", blogName);
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error updating blog likes status: {ex.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
connection.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int UpdateAPICount(string DBPath = @"TL.db")
|
public static int UpdateAPICount(string DBPath = @"TL.db")
|
||||||
{
|
{
|
||||||
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
SQLiteConnection connection = new SQLiteConnection("Data Source=" + DBPath);
|
||||||
@@ -908,6 +1177,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
|
||||||
Console.WriteLine(ex.Message);
|
Console.WriteLine(ex.Message);
|
||||||
}
|
}
|
||||||
@@ -928,10 +1198,11 @@ namespace URLNotesGrabberCORE
|
|||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
//string sql = "UPDATE Notes SET replyText = @replyText WHERE rootBlogName = @rootBlogName AND PostID = @PostID AND noteBlogName = @noteBlogName AND TimeStamp = @TimeStamp AND Type = 'reply'";
|
//string sql = "UPDATE Notes SET replyText = @replyText WHERE rootBlogName = @rootBlogName AND PostID = @PostID AND noteBlogName = @noteBlogName AND TimeStamp = @TimeStamp AND Type = 'reply'";
|
||||||
string sql = "UPDATE Notes SET replyText = @replyText WHERE PostID = @PostID AND noteBlogName = @noteBlogName AND TimeStamp = @TimeStamp AND Type = 'reply'";
|
string sql = "UPDATE Notes SET replyText = @replyText, DateModified = @dateModified WHERE PostID = @PostID AND noteBlogName = @noteBlogName AND TimeStamp = @TimeStamp AND Type = 'reply'";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@replyText", replyText ?? ".");
|
command.Parameters.AddWithValue("@replyText", replyText ?? ".");
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
||||||
command.Parameters.AddWithValue("@PostID", postID);
|
command.Parameters.AddWithValue("@PostID", postID);
|
||||||
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
|
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
|
||||||
@@ -952,6 +1223,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
Console.WriteLine($"[UpdateNoteReplyText] Error updating reply text: {ex.Message}");
|
Console.WriteLine($"[UpdateNoteReplyText] Error updating reply text: {ex.Message}");
|
||||||
Console.WriteLine($"[UpdateNoteReplyText] StackTrace: {ex.StackTrace}");
|
Console.WriteLine($"[UpdateNoteReplyText] StackTrace: {ex.StackTrace}");
|
||||||
}
|
}
|
||||||
@@ -969,10 +1241,11 @@ namespace URLNotesGrabberCORE
|
|||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
string sql = "UPDATE Notes SET replyText = @replyText WHERE rootBlogName = @rootBlogName AND PostID = @PostID AND Type = 'reply'";
|
string sql = "UPDATE Notes SET replyText = @replyText, DateModified = @dateModified WHERE rootBlogName = @rootBlogName AND PostID = @PostID AND Type = 'reply'";
|
||||||
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
|
||||||
{
|
{
|
||||||
command.Parameters.AddWithValue("@replyText", replyText ?? ".");
|
command.Parameters.AddWithValue("@replyText", replyText ?? ".");
|
||||||
|
command.Parameters.AddWithValue("@dateModified", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
|
||||||
command.Parameters.AddWithValue("@PostID", postID);
|
command.Parameters.AddWithValue("@PostID", postID);
|
||||||
int rowsAffected = command.ExecuteNonQuery();
|
int rowsAffected = command.ExecuteNonQuery();
|
||||||
@@ -991,6 +1264,7 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Breakpoint here
|
||||||
Console.WriteLine($"[UpdateAllNoteReplyTextForPost] Error updating reply text: {ex.Message}");
|
Console.WriteLine($"[UpdateAllNoteReplyTextForPost] Error updating reply text: {ex.Message}");
|
||||||
Console.WriteLine($"[UpdateAllNoteReplyTextForPost] StackTrace: {ex.StackTrace}");
|
Console.WriteLine($"[UpdateAllNoteReplyTextForPost] StackTrace: {ex.StackTrace}");
|
||||||
}
|
}
|
||||||
@@ -1027,6 +1301,65 @@ namespace URLNotesGrabberCORE
|
|||||||
private static string OAuthTokenSecret => Configuration["TumblrApi:OAuthTokenSecret"] ??
|
private static string OAuthTokenSecret => Configuration["TumblrApi:OAuthTokenSecret"] ??
|
||||||
throw new InvalidOperationException("OAuthTokenSecret is not configured");
|
throw new InvalidOperationException("OAuthTokenSecret is not configured");
|
||||||
|
|
||||||
|
private static int GetRetryDelaySecondsFromHeaders(IEnumerable<HeaderParameter>? headers)
|
||||||
|
{
|
||||||
|
if (headers == null)
|
||||||
|
return 60;
|
||||||
|
|
||||||
|
int retryInSeconds = 0;
|
||||||
|
bool remainingIsZero = false;
|
||||||
|
|
||||||
|
foreach (var header in headers)
|
||||||
|
{
|
||||||
|
string? headerName = header?.Name;
|
||||||
|
string? headerValue = header?.Value?.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(headerName) || string.IsNullOrWhiteSpace(headerValue))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (string.Equals(headerName, "Retry-After", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (int.TryParse(headerValue, out int retrySecs))
|
||||||
|
{
|
||||||
|
retryInSeconds = Math.Max(retryInSeconds, retrySecs);
|
||||||
|
}
|
||||||
|
else if (DateTimeOffset.TryParse(headerValue, out var retryAt))
|
||||||
|
{
|
||||||
|
int secs = (int)Math.Max(0, (retryAt - DateTimeOffset.UtcNow).TotalSeconds);
|
||||||
|
retryInSeconds = Math.Max(retryInSeconds, secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerName.IndexOf("X-RateLimit-Reset", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
{
|
||||||
|
if (long.TryParse(headerValue, out long epoch))
|
||||||
|
{
|
||||||
|
int secs = (int)Math.Max(0, epoch - DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||||
|
retryInSeconds = Math.Max(retryInSeconds, secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerName.Contains("Remaining", StringComparison.OrdinalIgnoreCase) && headerValue == "0")
|
||||||
|
{
|
||||||
|
remainingIsZero = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingIsZero && headerName.IndexOf("Reset", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
{
|
||||||
|
if (int.TryParse(headerValue, out int resetValue))
|
||||||
|
{
|
||||||
|
retryInSeconds = Math.Max(retryInSeconds, resetValue);
|
||||||
|
}
|
||||||
|
else if (long.TryParse(headerValue, out long resetEpoch))
|
||||||
|
{
|
||||||
|
int secs = (int)Math.Max(0, resetEpoch - DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||||
|
retryInSeconds = Math.Max(retryInSeconds, secs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retryInSeconds > 0 ? retryInSeconds : 60;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<Root> GrabNotes(string blog, long ID, string? timestamp = null)
|
public static async Task<Root> GrabNotes(string blog, long ID, string? timestamp = null)
|
||||||
{
|
{
|
||||||
var URL = "https://api.tumblr.com/v2/blog/[0].tumblr.com/notes?id=[1]&mode=all";
|
var URL = "https://api.tumblr.com/v2/blog/[0].tumblr.com/notes?id=[1]&mode=all";
|
||||||
@@ -1274,5 +1607,86 @@ namespace URLNotesGrabberCORE
|
|||||||
return myDeserializedClass;
|
return myDeserializedClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<LikesRoot> GrabLikes(string blog, long beforeTimestamp = 0)
|
||||||
|
{
|
||||||
|
var URL = $"https://api.tumblr.com/v2/blog/{Uri.EscapeDataString(blog)}.tumblr.com/likes?npf=false&reblog_info=true";
|
||||||
|
if (beforeTimestamp > 0)
|
||||||
|
{
|
||||||
|
URL += $"&before={beforeTimestamp}";
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var client = new RestClient(URL))
|
||||||
|
{
|
||||||
|
var oAuth1 = OAuth1Authenticator.ForAccessToken(consumerKey: ConsumerKey,
|
||||||
|
consumerSecret: ConsumerSecret,
|
||||||
|
token: OAuthToken,
|
||||||
|
tokenSecret: OAuthTokenSecret,
|
||||||
|
OAuthSignatureMethod.HmacSha1
|
||||||
|
);
|
||||||
|
|
||||||
|
client.Authenticator = oAuth1;
|
||||||
|
var request = new RestRequest(URL, Method.Get);
|
||||||
|
var response = await client.ExecuteAsync(request);
|
||||||
|
|
||||||
|
var myJsonResponse = response.Content ?? string.Empty;
|
||||||
|
Console.WriteLine($"[Likes API] {DateTime.Now}\t{DataAccess.UpdateAPICount()}");
|
||||||
|
var myDeserializedClass = new LikesRoot();
|
||||||
|
|
||||||
|
// Check if response is successful and contains JSON
|
||||||
|
if (!response.IsSuccessful || string.IsNullOrEmpty(myJsonResponse))
|
||||||
|
{
|
||||||
|
string? statusStr = null;
|
||||||
|
try { statusStr = response != null ? response.StatusCode.ToString() : null; } catch { statusStr = null; }
|
||||||
|
Console.WriteLine($"[Likes API] {statusStr}\t{response?.StatusDescription}");
|
||||||
|
if (!string.IsNullOrEmpty(statusStr))
|
||||||
|
myDeserializedClass.statusCode = statusStr;
|
||||||
|
|
||||||
|
if (response != null && response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
|
||||||
|
{
|
||||||
|
myDeserializedClass.statusCode = "TooManyRequests";
|
||||||
|
myDeserializedClass.retryInSeconds = GetRetryDelaySecondsFromHeaders(response.Headers);
|
||||||
|
}
|
||||||
|
return myDeserializedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myJsonResponse.TrimStart().StartsWith("<"))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Likes API] Received HTML response (likely error page): {response?.StatusCode}");
|
||||||
|
myDeserializedClass.statusCode = response?.StatusCode.ToString();
|
||||||
|
if (response != null && response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
|
||||||
|
{
|
||||||
|
myDeserializedClass.statusCode = "TooManyRequests";
|
||||||
|
myDeserializedClass.retryInSeconds = GetRetryDelaySecondsFromHeaders(response.Headers);
|
||||||
|
}
|
||||||
|
return myDeserializedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var deserializedResult = JsonConvert.DeserializeObject<LikesRoot>(myJsonResponse);
|
||||||
|
if (deserializedResult != null)
|
||||||
|
{
|
||||||
|
myDeserializedClass = deserializedResult;
|
||||||
|
myDeserializedClass.rawJson = myJsonResponse;
|
||||||
|
|
||||||
|
bool metaIndicatesRateLimit = myDeserializedClass.meta != null && myDeserializedClass.meta.status == 429;
|
||||||
|
bool statusIndicatesRateLimit = response != null && response.StatusCode == System.Net.HttpStatusCode.TooManyRequests;
|
||||||
|
|
||||||
|
if (metaIndicatesRateLimit || statusIndicatesRateLimit)
|
||||||
|
{
|
||||||
|
myDeserializedClass.statusCode = "TooManyRequests";
|
||||||
|
myDeserializedClass.retryInSeconds = GetRetryDelaySecondsFromHeaders(response?.Headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Likes API] Failed to parse JSON response: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return myDeserializedClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ namespace URLNotesGrabberCORE
|
|||||||
|
|
||||||
Console.WriteLine("-replies\t Fetch and update missing reply text for all replies in database");
|
Console.WriteLine("-replies\t Fetch and update missing reply text for all replies in database");
|
||||||
|
|
||||||
|
Console.WriteLine("-likes\t Fetch likes for all blogs needing it (LikesPulled=0), or a specific blog via param");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "-parse":
|
case "-parse":
|
||||||
@@ -185,6 +187,11 @@ namespace URLNotesGrabberCORE
|
|||||||
CollectMissingReplyText().GetAwaiter().GetResult();
|
CollectMissingReplyText().GetAwaiter().GetResult();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "-likes":
|
||||||
|
string likeBlog = args.Length > 1 ? args[1] : null;
|
||||||
|
CollectLikes(likeBlog, contains).GetAwaiter().GetResult();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Console.WriteLine("** Unknown Command ** " + args[0]);
|
Console.WriteLine("** Unknown Command ** " + args[0]);
|
||||||
break;
|
break;
|
||||||
@@ -442,13 +449,268 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async Task CollectLikes(string specificBlog, List<string> contains)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DataAccess.EnsureBlogsLikesColumnsExist();
|
||||||
|
|
||||||
|
Console.WriteLine("Starting collection of likes...");
|
||||||
|
var blogsToProcess = DataAccess.GetBlogsForLikes(specificBlog);
|
||||||
|
|
||||||
|
if (blogsToProcess.Count == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("No blogs found to process likes for.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"Found {blogsToProcess.Count} blogs to process likes.");
|
||||||
|
|
||||||
|
RateLimiter limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
|
||||||
|
{
|
||||||
|
PermitLimit = 300,
|
||||||
|
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
|
||||||
|
QueueLimit = 1,
|
||||||
|
Window = TimeSpan.FromMinutes(1),
|
||||||
|
SegmentsPerWindow = 60,
|
||||||
|
AutoReplenishment = true
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var blogInfo in blogsToProcess)
|
||||||
|
{
|
||||||
|
string blogName = blogInfo.Item1;
|
||||||
|
int likesPulled = blogInfo.Item2;
|
||||||
|
long cursor = blogInfo.Item3;
|
||||||
|
long parsedForBlog = 0;
|
||||||
|
long matchedForBlog = 0;
|
||||||
|
int likedCountForBlog = 0;
|
||||||
|
|
||||||
|
Console.WriteLine($"Processing likes for blog: {blogName} | Cursor: {cursor}");
|
||||||
|
|
||||||
|
bool hasMoreLikes = true;
|
||||||
|
|
||||||
|
while (hasMoreLikes)
|
||||||
|
{
|
||||||
|
using RateLimitLease lease = limiter.AttemptAcquire(1);
|
||||||
|
if (!lease.IsAcquired)
|
||||||
|
{
|
||||||
|
Console.WriteLine("!@@@@@@@ - Rate Limited Exceeded: No Lease Available");
|
||||||
|
return; // Might want to sleep instead, but this matches other functions
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await APIAccess.GrabLikes(blogName, cursor);
|
||||||
|
|
||||||
|
if (response?.statusCode == "NotFound" || (response?.meta != null && response.meta.status == 404))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"API returned 404 Not Found for {blogName} Likes");
|
||||||
|
// Set pulled = 1 to skip in future
|
||||||
|
DataAccess.UpdateBlogLikesStatus(blogName, 1, cursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response == null || response.statusCode == "TooManyRequests")
|
||||||
|
{
|
||||||
|
int retry = response?.retryInSeconds ?? 60;
|
||||||
|
if (retry <= 0)
|
||||||
|
retry = 60;
|
||||||
|
|
||||||
|
int remaining = retry;
|
||||||
|
DateTime retryUntil = DateTime.Now.AddSeconds(retry);
|
||||||
|
while (remaining > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Sleeping for {0} more seconds, until {1}", remaining, retryUntil.ToShortTimeString());
|
||||||
|
int sleepSeconds = Math.Min(60, remaining);
|
||||||
|
Thread.Sleep(sleepSeconds * 1000);
|
||||||
|
remaining -= sleepSeconds;
|
||||||
|
}
|
||||||
|
continue; // Retry same cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response?.response?.liked_posts == null || response.response.liked_posts.Count == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Likes] No more likes found for {blogName}. Marking complete.");
|
||||||
|
DataAccess.UpdateBlogLikesStatus(blogName, 1, cursor); // Done parsing
|
||||||
|
hasMoreLikes = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.response.liked_count > 0)
|
||||||
|
likedCountForBlog = response.response.liked_count;
|
||||||
|
|
||||||
|
Console.WriteLine($"[Likes] Fetched {response.response.liked_posts.Count} likes for {blogName}");
|
||||||
|
|
||||||
|
foreach (var post in response.response.liked_posts)
|
||||||
|
{
|
||||||
|
parsedForBlog++;
|
||||||
|
|
||||||
|
long postID = 0;
|
||||||
|
try { postID = Convert.ToInt64(post.id); } catch { continue; }
|
||||||
|
|
||||||
|
string authorBlog = post.blog_name?.ToString() ?? ".";
|
||||||
|
string postURL = post.post_url?.ToString() ?? ".";
|
||||||
|
string date = post.date?.ToString() ?? ".";
|
||||||
|
|
||||||
|
// Legacy format fields
|
||||||
|
string body = post.body?.ToString() ?? ".";
|
||||||
|
string summary = post.summary?.ToString() ?? ".";
|
||||||
|
string slug = post.slug?.ToString() ?? ".";
|
||||||
|
string reblogURL = post.source_url?.ToString() ?? ".";
|
||||||
|
string reblogName = post.reblogged_from_name?.ToString() ?? post.source_title?.ToString() ?? ".";
|
||||||
|
string rootBlogName = post.reblogged_root_name?.ToString() ?? ".";
|
||||||
|
string rootURL = post.reblogged_root_url?.ToString() ?? ".";
|
||||||
|
|
||||||
|
// Quick check for tags
|
||||||
|
string tags = ".";
|
||||||
|
if (post.tags != null)
|
||||||
|
{
|
||||||
|
try { tags = string.Join(", ", post.tags); }
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasImage = false;
|
||||||
|
string photoURL = ".";
|
||||||
|
string photoCaption = ".";
|
||||||
|
|
||||||
|
if (post.photos != null)
|
||||||
|
{
|
||||||
|
hasImage = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var firstPhoto = post.photos[0];
|
||||||
|
if (firstPhoto != null)
|
||||||
|
{
|
||||||
|
if (firstPhoto.original_size != null)
|
||||||
|
photoURL = firstPhoto.original_size.url?.ToString() ?? ".";
|
||||||
|
photoCaption = firstPhoto.caption?.ToString() ?? ".";
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
else if (body.IndexOf("<img", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
{
|
||||||
|
hasImage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional fields
|
||||||
|
string quote = ".";
|
||||||
|
string audioCaption = ".";
|
||||||
|
string question = ".";
|
||||||
|
string answer = ".";
|
||||||
|
string title = post.title?.ToString() ?? ".";
|
||||||
|
string downloadedFiles = ".";
|
||||||
|
string reblogKey = post.reblog_key?.ToString() ?? ".";
|
||||||
|
string link = ".";
|
||||||
|
|
||||||
|
// Only insert if any of the data contains strings from ContainsList
|
||||||
|
bool shouldInsert = false;
|
||||||
|
string matchedFieldName = string.Empty;
|
||||||
|
|
||||||
|
// Let's check a few fields that usually have URLs or relevant info that might match ContainsList
|
||||||
|
var fieldsToCheck = new (string Name, string Value)[] {
|
||||||
|
("postURL", postURL),
|
||||||
|
("authorBlog", authorBlog),
|
||||||
|
("reblogURL", reblogURL),
|
||||||
|
("reblogName", reblogName),
|
||||||
|
("rootBlogName", rootBlogName),
|
||||||
|
("rootURL", rootURL),
|
||||||
|
("summary", summary),
|
||||||
|
("body", body),
|
||||||
|
("tags", tags),
|
||||||
|
("photoURL", photoURL),
|
||||||
|
("photoCaption", photoCaption),
|
||||||
|
("quote", quote),
|
||||||
|
("question", question),
|
||||||
|
("answer", answer),
|
||||||
|
("downloadedFiles", downloadedFiles),
|
||||||
|
("slug", slug)
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var field in fieldsToCheck)
|
||||||
|
{
|
||||||
|
if (ContainsAny(field.Value, contains))
|
||||||
|
{
|
||||||
|
shouldInsert = true;
|
||||||
|
matchedFieldName = field.Name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldInsert)
|
||||||
|
{
|
||||||
|
matchedForBlog++;
|
||||||
|
Console.WriteLine($"[Likes] Match | Author: {authorBlog} | PostID: {postID} | Field: {matchedFieldName}");
|
||||||
|
await Task.Delay(3000);
|
||||||
|
DataAccess.AddPost(authorBlog, postID, reblogURL, date, postURL, slug, reblogKey,
|
||||||
|
reblogName, summary, quote, body, tags, link, photoURL,
|
||||||
|
photoCaption, downloadedFiles, audioCaption, question, answer,
|
||||||
|
title, hasImage, true, rootBlogName: rootBlogName, rootURL: rootURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likedCountForBlog > 0)
|
||||||
|
{
|
||||||
|
double parsedPct = (double)parsedForBlog / likedCountForBlog * 100.0;
|
||||||
|
double matchedPct = (double)matchedForBlog / likedCountForBlog * 100.0;
|
||||||
|
Console.WriteLine($"[Likes] {blogName} Running Totals | Parsed: {parsedForBlog}/{likedCountForBlog} ({parsedPct:F2}%) | Matched: {matchedForBlog}/{likedCountForBlog} ({matchedPct:F2}%)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Likes] {blogName} Running Totals | Parsed: {parsedForBlog} | Matched: {matchedForBlog}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the next BeforeCursor.
|
||||||
|
long nextCursor = 0;
|
||||||
|
if (response.response._links?.next?.query_params != null)
|
||||||
|
{
|
||||||
|
long.TryParse(response.response._links.next.query_params.before ?? "0", out nextCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist cursor progress after every page so resume is always up-to-date
|
||||||
|
long cursorToPersist = nextCursor > 0 ? nextCursor : cursor;
|
||||||
|
DataAccess.UpdateBlogLikesStatus(blogName, 0, cursorToPersist);
|
||||||
|
|
||||||
|
if (nextCursor > 0)
|
||||||
|
{
|
||||||
|
cursor = nextCursor;
|
||||||
|
Console.WriteLine($"[Likes] Pagination Next Cursor: {cursor}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Likes] No further pagination items. Done with {blogName}.");
|
||||||
|
DataAccess.UpdateBlogLikesStatus(blogName, 1, cursorToPersist); // Mark as completely pulled
|
||||||
|
hasMoreLikes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(1000); // 1-second delay between pages
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likedCountForBlog > 0)
|
||||||
|
{
|
||||||
|
double parsedPct = (double)parsedForBlog / likedCountForBlog * 100.0;
|
||||||
|
double matchedPct = (double)matchedForBlog / likedCountForBlog * 100.0;
|
||||||
|
Console.WriteLine($"[Likes] {blogName} Final Totals | Parsed: {parsedForBlog}/{likedCountForBlog} ({parsedPct:F2}%) | Matched: {matchedForBlog}/{likedCountForBlog} ({matchedPct:F2}%)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[Likes] {blogName} Final Totals | Parsed: {parsedForBlog} | Matched: {matchedForBlog}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Likes collection complete.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error collecting likes: {ex.Message}");
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async Task<string> GrabNotes(Tuple<string, long, long, long> post)
|
static async Task<string> GrabNotes(Tuple<string, long, long, long> post)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int APICount = DataAccess.GetAPICount();
|
int APICount = DataAccess.GetAPICount();
|
||||||
Console.WriteLine($"{post.Item1}\t{post.Item2}\t{DateTime.Now}\t{APICount}");
|
Console.WriteLine($"{post.Item1}\t{post.Item2}\t{DateTime.Now}\t{APICount}");
|
||||||
Thread.Sleep(3000);
|
//Thread.Sleep(3000);
|
||||||
|
|
||||||
var allNotes = new List<dynamic>();
|
var allNotes = new List<dynamic>();
|
||||||
int page = 1;
|
int page = 1;
|
||||||
@@ -478,10 +740,10 @@ namespace URLNotesGrabberCORE
|
|||||||
}
|
}
|
||||||
if (response.statusCode == "TooManyRequests")
|
if (response.statusCode == "TooManyRequests")
|
||||||
{
|
{
|
||||||
for (int s = 0; s <= response.retryInSeconds; s += 15)
|
for (int s = 0; s <= response.retryInSeconds; s += 60)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Sleeping for {0} more seconds, until {1}", response.retryInSeconds - s, DateTime.Now.AddSeconds(response.retryInSeconds - s).ToShortTimeString());
|
Console.WriteLine("Sleeping for {0} more seconds, until {1}", response.retryInSeconds - s, DateTime.Now.AddSeconds(response.retryInSeconds - s).ToShortTimeString());
|
||||||
Thread.Sleep(15000);
|
Thread.Sleep(60000);
|
||||||
}
|
}
|
||||||
return response.statusCode;
|
return response.statusCode;
|
||||||
}
|
}
|
||||||
@@ -589,6 +851,12 @@ namespace URLNotesGrabberCORE
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("GrabNotes Result: " + status);
|
Console.WriteLine("GrabNotes Result: " + status);
|
||||||
|
|
||||||
|
//if not success, mark as not found to avoid repeated attempts, unless it was a rate limit issue
|
||||||
|
if (status != "RateLimitExceeded")
|
||||||
|
{
|
||||||
|
DataAccess.UpdatePostMarkNotFound(post.Item1, post.Item2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-fetch the updated list after processing the current post
|
// Re-fetch the updated list after processing the current post
|
||||||
@@ -652,7 +920,7 @@ namespace URLNotesGrabberCORE
|
|||||||
postsAdded++;
|
postsAdded++;
|
||||||
|
|
||||||
// Output hyperlink and post date
|
// Output hyperlink and post date
|
||||||
Console.WriteLine($"https://{reblog.reblogName}.tumblr.com/post/{reblog.postID} - {reblog.date}");
|
//Console.WriteLine($"https://{reblog.reblogName}.tumblr.com/post/{reblog.postID} - {reblog.date}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reblog = new ReblogRecord();
|
reblog = new ReblogRecord();
|
||||||
@@ -773,7 +1041,7 @@ namespace URLNotesGrabberCORE
|
|||||||
postsAdded++;
|
postsAdded++;
|
||||||
|
|
||||||
// Output hyperlink and post date
|
// Output hyperlink and post date
|
||||||
Console.WriteLine($"https://{reblog.reblogName}.tumblr.com/post/{reblog.postID} - {reblog.date}");
|
//Console.WriteLine($"https://{reblog.reblogName}.tumblr.com/post/{reblog.postID} - {reblog.date}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"URLNotesGrabberCORE": {
|
"URLNotesGrabberCORE": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"commandLineArgs": "-collect 1"
|
"commandLineArgs": "-likes timothywrite"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +58,8 @@ namespace URLNotesGrabberCORE
|
|||||||
public string mode { get; set; }
|
public string mode { get; set; }
|
||||||
public string id { get; set; }
|
public string id { get; set; }
|
||||||
public string before_timestamp { get; set; }
|
public string before_timestamp { get; set; }
|
||||||
|
public string before { get; set; }
|
||||||
|
public string after { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Response
|
public class Response
|
||||||
@@ -116,4 +118,22 @@ namespace URLNotesGrabberCORE
|
|||||||
|
|
||||||
public string rawJson { get; set; }
|
public string rawJson { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LikesResponse
|
||||||
|
{
|
||||||
|
public List<dynamic> liked_posts { get; set; }
|
||||||
|
public int liked_count { get; set; }
|
||||||
|
public Links _links { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LikesRoot
|
||||||
|
{
|
||||||
|
public Meta meta { get; set; }
|
||||||
|
[JsonConverter(typeof(EmptyArrayOrObjectConverter<LikesResponse>))]
|
||||||
|
public LikesResponse response { get; set; }
|
||||||
|
|
||||||
|
public string statusCode { get; set; }
|
||||||
|
public int retryInSeconds { get; set; }
|
||||||
|
public string rawJson { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"PathOutputBlogs": "u:\\jim\\Documents\\Web Copies\\blogs\\GetBlogs.txt",
|
"PathOutputBlogs": "u:\\jim\\Documents\\Web Copies\\blogs\\GetBlogs.txt",
|
||||||
"PathOutputReplies": "u:\\jim\\Documents\\Web Copies\\blogs\\GetReplies.txt",
|
"PathOutputReplies": "u:\\jim\\Documents\\Web Copies\\blogs\\GetReplies.txt",
|
||||||
"PathDB": "u:\\jim\\Documents\\Web Copies\\blogs\\TL.db",
|
"PathDB": "u:\\jim\\Documents\\Web Copies\\blogs\\TL.db",
|
||||||
"ContainsList": "zombaee,zomb-eh,ahzombae,thebugandme,lovingbabybug,swarthyvillain,h4rdspot"
|
"ContainsList": "zombaee,zomb-eh,ahzombae,thebugandme,lovingbabybug,h4rdspot",
|
||||||
|
"PostIDToExclude": "730084470076686336,726309940037287936,639974102120235008,184045126218"
|
||||||
},
|
},
|
||||||
"TumblrApi": {
|
"TumblrApi": {
|
||||||
"ConsumerKey": "PtsBCGumcsgihyynxUh8b47Jfmi7uXhEIOU46bmhdsUSJ5mEP3",
|
"ConsumerKey": "PtsBCGumcsgihyynxUh8b47Jfmi7uXhEIOU46bmhdsUSJ5mEP3",
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
@echo off
|
||||||
|
REM Batch file to run URLNotesGrabberCORE 500 times in a loop
|
||||||
|
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
REM Set the path to the executable
|
||||||
|
REM Update this path if your executable is in a different location
|
||||||
|
set APP_PATH=URLNotesGrabberCORE.exe
|
||||||
|
|
||||||
|
REM Check if the executable exists
|
||||||
|
if not exist "%APP_PATH%" (
|
||||||
|
echo Error: %APP_PATH% not found in the current directory.
|
||||||
|
echo Please ensure the executable is in the same directory as this batch file,
|
||||||
|
echo or update the APP_PATH variable with the correct path.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Loop counter
|
||||||
|
set ITERATIONS=500
|
||||||
|
set COUNTER=0
|
||||||
|
|
||||||
|
echo Starting to run %APP_PATH% %ITERATIONS% times...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:LOOP
|
||||||
|
set /a COUNTER+=1
|
||||||
|
echo [%COUNTER%/%ITERATIONS%] Running iteration %COUNTER%...
|
||||||
|
echo Started at: %date% %time%
|
||||||
|
|
||||||
|
REM Run the application with -replies option
|
||||||
|
call "%APP_PATH%" -replies
|
||||||
|
|
||||||
|
REM Check if the application ran successfully
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Warning: Application exited with error code !ERRORLEVEL! on iteration %COUNTER%
|
||||||
|
) else (
|
||||||
|
echo Iteration %COUNTER% completed successfully.
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Completed at: %date% %time%
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Check if we've reached 500 iterations
|
||||||
|
if %COUNTER% lss %ITERATIONS% (
|
||||||
|
goto LOOP
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Completed all %ITERATIONS% iterations!
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
Reference in New Issue
Block a user