diff --git a/AutoLikerCefSharpWpf/App.config b/AutoLikerCefSharpWpf/App.config
index 56efbc7..ad4a485 100644
--- a/AutoLikerCefSharpWpf/App.config
+++ b/AutoLikerCefSharpWpf/App.config
@@ -1,6 +1,36 @@
+
+
+
+
+
+
+
+
+ travelphotography,familyphotographer
+
+
+ 45
+
+
+ 60
+
+
+ 10
+
+
+ 25
+
+
+ 5
+
+
+ 15
+
+
+
\ No newline at end of file
diff --git a/AutoLikerCefSharpWpf/Assets/autotag_injection.js b/AutoLikerCefSharpWpf/Assets/autotag_injection.js
new file mode 100644
index 0000000..076ffc6
--- /dev/null
+++ b/AutoLikerCefSharpWpf/Assets/autotag_injection.js
@@ -0,0 +1,277 @@
+// https://jscompress.com/
+
+function alObject() {
+ this._tag = "";
+ this._posts = {};
+ this._maxLikes = 3;
+ this._likesMin = 5;
+ this._likesMax = 10;
+ this._delayRestart = 15; // minutes
+ this._delayRestartMin = 15; // minutes
+ this._delayRestartMax = 30; // minutes
+ this._delayPerLikeMin = 5; // seconds
+ this._delayPerLikeMax = 10; // seconds
+ this._endCursor = ""; // needed?
+ this._failedRetriesMax = 2;
+ this._failedRetries = 0;
+ this._instagramBaseUrl = "https://www.instagram.com";
+ this._postItems = [];
+ this._scrollOffset = null;
+}
+
+alObject.prototype.initializeSettings = function(tag, likesMin, likesMax, delayMin, delayMax, delayRestartMin, delayRestartMax) {
+ this._tag = tag;
+ this._likesMin = likesMin;
+ this._likesMax = likesMax;
+ this._delayPerLikeMin = delayMin;
+ this._delayPerLikeMax = delayMax;
+ this._delayRestartMin = delayRestartMin;
+ this._delayRestartMax = delayRestartMax;
+ console.log("tag:" + tag + " | likesMin:" + likesMin + " | likesMax:" + likesMax + " | delayMin: " + delayMin + " | delayMax: " + delayMax + " | delayRestartMin: " + delayRestartMin + " | delayRestartMax: " + delayRestartMax);
+ this._maxLikes = this.getRandomInt(this._likesMin, this._likesMax);
+ this._delayRestart = this.getRandomInt(this._delayRestartMin, this._delayRestartMax);
+ console.log("_maxLikes: " + this._maxLikes);
+ console.log("_delayRestart (min): " + this._delayRestart);
+ if (this._tag.includes(",")) {
+ let tags = this._tag.split(",");
+ console.log(tags);
+ console.log("tags length: " + tags.length);
+ let pick = this.getRandomInt(0, tags.length - 1);
+ let picked_tag = tags[pick].trim();
+ console.log("picked tag: " + picked_tag);
+ this._tag = picked_tag;
+ }
+}
+
+alObject.prototype.instagramStartClickProcess = function(retry=true) {
+ let thisObj = this;
+ thisObj._postItems = [];
+ console.log('*** instagramStartClickProcess ***');
+ window.scrollTo(0,0);
+ thisObj.runDelay(10000, () => {
+ thisObj.log((new Date()).toLocaleString() + ': Starting click process ..');
+ let top_posts = jQuery('h2').eq(0);
+ let most_recent = jQuery('h2').eq(1);
+ let jump_to_section = null;
+ if (most_recent.length > 0) {
+ jump_to_section = most_recent;
+ } else if (most_recent.length == 0 && top_posts.length > 0) {
+ jump_to_section = top_posts;
+ }
+
+ if (jump_to_section == null || jump_to_section == 0) {
+ thisObj.log('ERROR: couldn\'t find most recent or top posts sections!');
+ if (retry) {
+ thisObj.log(' - retrying after 60 seconds (to give IG time to load).');
+ thisObj.runDelay(60000, () => {
+ thisObj.instagramStartClickProcess(false);
+ });
+ } else {
+ thisObj.runDelay(1000, () => {
+ thisObj.restartProcess();
+ });
+ }
+
+ } else {
+ let mr_div = jump_to_section.next();
+ thisObj.log('Scroll to list ..');
+ jQuery('html, body').animate({ scrollTop: mr_div.offset().top }, 500);
+ let parentX = mr_div.offset().left;
+ let parentY = mr_div.offset().top;
+ thisObj._scrollOffset = mr_div.offset();
+ console.log('parentX: ' + parentX + ' ; parentY: ' + parentY);
+ thisObj.runDelay(2000, () => {
+ let child01 = mr_div.children('div').eq(0);
+ let postLinks = child01.find('a');
+ postLinks.each( function(i) {
+ thisObj._postItems.push(jQuery(this).attr('href'));
+ });
+ console.log('items:');
+ console.log(thisObj._postItems);
+ thisObj.log('Found posts: ' + thisObj._postItems.length);
+ // get first post
+ let element01 = jQuery('a[href="' + thisObj._postItems[0] + '"]');
+ console.log(element01);
+ let element02 = element01.find('img').eq(0);
+ console.log(element02);
+ console.log(element02.attr('src'));
+ if (element02) {
+ console.log('imgX: ' + element02.offset().left + ' ; imgY: ' + element02.offset().top);
+ //let clickX = parseInt(parentX - element02.offset().left) + 1;
+ let clickX = parseInt(element02.offset().left) + 30;
+ let clickY = parseInt(parentY - element02.offset().top) + 60;
+ console.log('clickX: ' + clickX + ' ; clickY: ' + clickY);
+ thisObj.log('Will like this many posts: ' + thisObj._maxLikes);
+ thisObj.instagramClickPost(element02, clickX, clickY);
+ }
+ });
+ }
+ });
+}
+
+alObject.prototype.instagramClickPost = function(img, x, y) {
+ let thisObj = this;
+ thisObj.log('Click on initial post ..');
+ boundAsync.singleLeftClick(x, y).then( (res1) => {
+ console.log('Left Click');
+ //console.log('jQuery(window).scrollLeft(): ' + jQuery(window).scrollLeft() + ' ; jQuery(window).scrollTop(): ' + jQuery(window).scrollTop());
+ thisObj.runDelay(8000, () => {
+ thisObj.instagramLoopOverPostsClick();
+ });
+ });
+}
+
+alObject.prototype.instagramLoopOverPostsClick = function(index) {
+ let thisObj = this;
+ // initial index
+ if (!index) {
+ index = 1;
+ }
+ thisObj.log("Like post; " + index + " of " + thisObj._maxLikes);
+ // like button
+ //let likeBtn = jQuery('body').find('span._aamw button._abl-').eq(0); // Update: 2022-06-11
+ let likeBtn = jQuery('body').find('span._aamw span:has(svg)').eq(0); // Update: 2023-09-12
+ console.log('likeBtn:');
+ console.log(likeBtn);
+ // next button
+ //let nextBtn = jQuery('a.coreSpriteRightPaginationArrow').eq(0);
+ //let nextBtn = jQuery('div.l8mY4 button.wpO6b');
+ let nextBtn = jQuery('div._aaqg button._abl-');
+ console.log('nextBtn:');
+ console.log(nextBtn);
+ // check if like button exists, if not restart
+ if (likeBtn.length == 0) {
+ thisObj.log(' - Could not find the "Like" button :(');
+ if (nextBtn.length > 0) {
+ thisObj.instagramClickNextButton(nextBtn, index);
+ } else {
+ thisObj.restartProcess();
+ }
+ }
+ // offsets and coordinates
+ let btnOffset = likeBtn.offset();
+ let clickY = parseInt(btnOffset.top - jQuery(window).scrollTop());
+ let clickX = parseInt(btnOffset.left - jQuery(window).scrollLeft());
+ console.log('likeBtn = clickX: ' + clickX + ' ; clickY: ' + clickY);
+ // like text
+ //let likeSpan = likeBtn.children().eq(0);
+ let likeImage = likeBtn.find('svg').eq(0);
+ let likeText = likeImage.attr('aria-label');
+ console.log('Like Text: ' + likeText);
+ if (likeText === 'Like') {
+ // post hasn't been liked yet
+ // generate delay
+ let delayBeforeLike = thisObj.getRandomInt(thisObj._delayPerLikeMin, thisObj._delayPerLikeMax);
+ let delayBeforeLikeMs = delayBeforeLike * 1000;
+ thisObj.log(" - not liked yet; delay before clicking like = " + delayBeforeLike + " sec");
+ // delay like
+ thisObj.runDelay(delayBeforeLikeMs, () => {
+ thisObj.log(" - initiating clicking Like button ..");
+ boundAsync.singleLeftClick(clickX+10, clickY+10).then( result => {
+ thisObj.log(" - clicked Like button .. wait to confirm ..");
+ // check if post is actually liked
+ thisObj.runDelay(4000, () => {
+ likeText = jQuery('body').find('span._aamw svg').eq(0).attr('aria-label'); // Update: 2023-09-12
+ console.log('Like Text: ' + likeText);
+ if (likeText !== 'Like') {
+ thisObj.log(" - Successfully liked!");
+ thisObj.instagramClickNextButton(nextBtn, index);
+ } else {
+ // POST NOT LIKED! POTENTIALLY DUE TO INSTAGRAM BLOCK
+ // Stop processing
+ thisObj.log(" - POST NOT LIKED! BLOCKED??");
+ thisObj.log("*** STOPPING ***");
+ thisObj.restartProcess();
+ }
+ });
+ }, reason => {
+ thisObj.log(" - Error liking! Reason = " + reason);
+ thisObj.instagramClickNextButton(nextBtn, index);
+ });
+ });
+ } else {
+ // already liked, go to the next item
+ thisObj.log(" - already liked this post!");
+ thisObj.instagramClickNextButton(nextBtn, index);
+ }
+}
+
+alObject.prototype.instagramClickNextButton = function(nextBtn, i) {
+ let thisObj = this;
+ if (i < thisObj._maxLikes) {
+ thisObj.log(" - Waiting before clicking on next button ..");
+ let nextBtnOffset = nextBtn.offset();
+ console.log(nextBtnOffset);
+ let nextY = parseInt(nextBtnOffset.top - jQuery(window).scrollTop());
+ let nextX = parseInt(nextBtnOffset.left - jQuery(window).scrollLeft());
+ console.log('nextBtn = nextX: ' + nextX + ' ; nextY: ' + nextY);
+ thisObj.runDelay(3000, () => {
+ boundAsync.singleLeftClick(nextX+10, nextY+10).then(result => {
+ thisObj.log(" - Successfully went to the next post! Wait 5 sec ..");
+ thisObj.runDelay(5000, () => {
+ let newIndex = i + 1;
+ thisObj.instagramLoopOverPostsClick(newIndex);
+ });
+ }, reason => {
+ thisObj.log(" - Error going to the next post! Reason = " + reason);
+ });
+ });
+ } else {
+ thisObj.log(" - Reached end of list of posts, restarting process ..");
+ thisObj.runDelay(3000, () => {
+ thisObj.restartProcess();
+ });
+ }
+}
+
+alObject.prototype.restartProcess = function() {
+ let thisObj = this;
+ console.log('*** restartProcess ***');
+ if (boundAsync) {
+ let restart;
+ if (thisObj._delayRestart) {
+ restart = thisObj._delayRestart;
+ } else {
+ restart = 15;
+ }
+ let restartMs = restart * 60000;
+ let nowDate = new Date();
+ var newDateObj = new Date(nowDate.getTime() + restartMs);
+ thisObj.log(nowDate.toLocaleString() + ": RESTARTING in (min): " + restart);
+ thisObj.log(" - Reloading at: " + newDateObj.toLocaleString());
+ thisObj.runDelay(restartMs, () => {
+ boundAsync.restartProcess().then(result => {
+ console.log('reloading ..');
+ });
+ });
+ }
+}
+
+/**
+* Delay function
+**/
+alObject.prototype.runDelay = function(Delay, CallbackFunc) {
+ setTimeout(CallbackFunc, Delay);
+}
+
+/**
+* Logging function
+**/
+alObject.prototype.log = function(msg) {
+ console.log(msg);
+ if (boundAsync) {
+ boundAsync.logMessage(msg).then(result => {
+ // successful result
+ }, reason => {
+ console.error(reason);
+ });
+ }
+}
+
+/**
+ * Returns a random integer between min (inclusive) and max (inclusive)
+ * Using Math.round() will give you a non-uniform distribution!
+ */
+alObject.prototype.getRandomInt = function(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
\ No newline at end of file
diff --git a/AutoLikerCefSharpWpf/Assets/autotag_injection_min.js b/AutoLikerCefSharpWpf/Assets/autotag_injection_min.js
new file mode 100644
index 0000000..97cc576
--- /dev/null
+++ b/AutoLikerCefSharpWpf/Assets/autotag_injection_min.js
@@ -0,0 +1 @@
+function alObject() { this._tag = "", this._posts = {}, this._maxLikes = 3, this._likesMin = 5, this._likesMax = 10, this._delayRestart = 15, this._delayRestartMin = 15, this._delayRestartMax = 30, this._delayPerLikeMin = 5, this._delayPerLikeMax = 10, this._endCursor = "", this._failedRetriesMax = 2, this._failedRetries = 0, this._instagramBaseUrl = "https://www.instagram.com", this._postItems = [], this._scrollOffset = null } alObject.prototype.initializeSettings = function (t, e, o, s, l, n, i) { if (this._tag = t, this._likesMin = e, this._likesMax = o, this._delayPerLikeMin = s, this._delayPerLikeMax = l, this._delayRestartMin = n, this._delayRestartMax = i, console.log("tag:" + t + " | likesMin:" + e + " | likesMax:" + o + " | delayMin: " + s + " | delayMax: " + l + " | delayRestartMin: " + n + " | delayRestartMax: " + i), this._maxLikes = this.getRandomInt(this._likesMin, this._likesMax), this._delayRestart = this.getRandomInt(this._delayRestartMin, this._delayRestartMax), console.log("_maxLikes: " + this._maxLikes), console.log("_delayRestart (min): " + this._delayRestart), this._tag.includes(",")) { let t = this._tag.split(","); console.log(t), console.log("tags length: " + t.length); i = this.getRandomInt(0, t.length - 1), i = t[i].trim(); console.log("picked tag: " + i), this._tag = i } }, alObject.prototype.instagramStartClickProcess = function (s = !0) { var r = this; r._postItems = [], console.log("*** instagramStartClickProcess ***"), window.scrollTo(0, 0), r.runDelay(1e4, () => { r.log((new Date).toLocaleString() + ": Starting click process .."); var t = jQuery("h2").eq(0), e = jQuery("h2").eq(1); let o = null; if (0 < e.length ? o = e : 0 == e.length && 0 < t.length && (o = t), null == o || 0 == o) r.log("ERROR: couldn't find most recent or top posts sections!"), s ? (r.log(" - retrying after 60 seconds (to give IG time to load)."), r.runDelay(6e4, () => { r.instagramStartClickProcess(!1) })) : r.runDelay(1e3, () => { r.restartProcess() }); else { let i = o.next(); r.log("Scroll to list .."), jQuery("html, body").animate({ scrollTop: i.offset().top }, 500); var t = i.offset().left, a = i.offset().top; r._scrollOffset = i.offset(), console.log("parentX: " + t + " ; parentY: " + a), r.runDelay(2e3, () => { let t = i.children("div").eq(0), e = t.find("a"); e.each(function (t) { r._postItems.push(jQuery(this).attr("href")) }), console.log("items:"), console.log(r._postItems), r.log("Found posts: " + r._postItems.length); let o = jQuery('a[href="' + r._postItems[0] + '"]'); console.log(o); let s = o.find("img").eq(0); var l, n; console.log(s), console.log(s.attr("src")), s && (console.log("imgX: " + s.offset().left + " ; imgY: " + s.offset().top), l = parseInt(s.offset().left) + 30, n = parseInt(a - s.offset().top) + 60, console.log("clickX: " + l + " ; clickY: " + n), r.log("Will like this many posts: " + r._maxLikes), r.instagramClickPost(s, l, n)) }) } }) }, alObject.prototype.instagramClickPost = function (t, e, o) { var s = this; s.log("Click on initial post .."), boundAsync.singleLeftClick(e, o).then(t => { console.log("Left Click"), s.runDelay(8e3, () => { s.instagramLoopOverPostsClick() }) }) }, alObject.prototype.instagramLoopOverPostsClick = function (e) { var o = this; e = e || 1, o.log("Like post; " + e + " of " + o._maxLikes); let t = jQuery("body").find("span._aamw span:has(svg)").eq(0); console.log("likeBtn:"), console.log(t); var s = jQuery("div._aaqg button._abl-"); console.log("nextBtn:"), console.log(s), 0 == t.length && (o.log(' - Could not find the "Like" button :('), 0 < s.length ? o.instagramClickNextButton(s, e) : o.restartProcess()); var l = t.offset(), n = parseInt(l.top - jQuery(window).scrollTop()), i = parseInt(l.left - jQuery(window).scrollLeft()); console.log("likeBtn = clickX: " + i + " ; clickY: " + n); let a = t.find("svg").eq(0); var r, c = a.attr("aria-label"); console.log("Like Text: " + c), "Like" === c ? (l = 1e3 * (r = o.getRandomInt(o._delayPerLikeMin, o._delayPerLikeMax)), o.log(" - not liked yet; delay before clicking like = " + r + " sec"), o.runDelay(l, () => { o.log(" - initiating clicking Like button .."), boundAsync.singleLeftClick(i + 10, n + 10).then(t => { o.log(" - clicked Like button .. wait to confirm .."), o.runDelay(4e3, () => { c = jQuery("body").find("span._aamw svg").eq(0).attr("aria-label"), console.log("Like Text: " + c), "Like" !== c ? (o.log(" - Successfully liked!"), o.instagramClickNextButton(s, e)) : (o.log(" - POST NOT LIKED! BLOCKED??"), o.log("*** STOPPING ***"), o.restartProcess()) }) }, t => { o.log(" - Error liking! Reason = " + t), o.instagramClickNextButton(s, e) }) })) : (o.log(" - already liked this post!"), o.instagramClickNextButton(s, e)) }, alObject.prototype.instagramClickNextButton = function (t, e) { var o, s, l = this; e < l._maxLikes ? (l.log(" - Waiting before clicking on next button .."), t = t.offset(), console.log(t), o = parseInt(t.top - jQuery(window).scrollTop()), s = parseInt(t.left - jQuery(window).scrollLeft()), console.log("nextBtn = nextX: " + s + " ; nextY: " + o), l.runDelay(3e3, () => { boundAsync.singleLeftClick(s + 10, o + 10).then(t => { l.log(" - Successfully went to the next post! Wait 5 sec .."), l.runDelay(5e3, () => { var t = e + 1; l.instagramLoopOverPostsClick(t) }) }, t => { l.log(" - Error going to the next post! Reason = " + t) }) })) : (l.log(" - Reached end of list of posts, restarting process .."), l.runDelay(3e3, () => { l.restartProcess() })) }, alObject.prototype.restartProcess = function () { var o = this; if (console.log("*** restartProcess ***"), boundAsync) { let t; t = o._delayRestart || 15; var s = 6e4 * t; let e = new Date; var l = new Date(e.getTime() + s); o.log(e.toLocaleString() + ": RESTARTING in (min): " + t), o.log(" - Reloading at: " + l.toLocaleString()), o.runDelay(s, () => { boundAsync.restartProcess().then(t => { console.log("reloading ..") }) }) } }, alObject.prototype.runDelay = function (t, e) { setTimeout(e, t) }, alObject.prototype.log = function (t) { console.log(t), boundAsync && boundAsync.logMessage(t).then(t => { }, t => { console.error(t) }) }, alObject.prototype.getRandomInt = function (t, e) { return Math.floor(Math.random() * (e - t + 1)) + t };
\ No newline at end of file
diff --git a/AutoLikerCefSharpWpf/AutoLikerCefSharpWpf.csproj b/AutoLikerCefSharpWpf/AutoLikerCefSharpWpf.csproj
index 7a88246..c99d27e 100644
--- a/AutoLikerCefSharpWpf/AutoLikerCefSharpWpf.csproj
+++ b/AutoLikerCefSharpWpf/AutoLikerCefSharpWpf.csproj
@@ -115,6 +115,10 @@
MSBuild:Compile
Designer
+
+
+
+
MSBuild:Compile
Designer
@@ -177,6 +181,10 @@
+
+
+
+
diff --git a/AutoLikerCefSharpWpf/Converter/TitleConverter.cs b/AutoLikerCefSharpWpf/Converter/TitleConverter.cs
index e96cb23..37f21dc 100644
--- a/AutoLikerCefSharpWpf/Converter/TitleConverter.cs
+++ b/AutoLikerCefSharpWpf/Converter/TitleConverter.cs
@@ -13,7 +13,7 @@ namespace AutoLikerCefSharpWpf.Converter
#endif
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- return "AutoLikerCefSharpWpf (" + Build + ") - " + (value ?? "No Title Specified");
+ return "AutoLiker v2 (" + Build + ") - " + (value ?? "No Title Specified");
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/AutoLikerCefSharpWpf/Helper/AutoLikerSettingsManager.cs b/AutoLikerCefSharpWpf/Helper/AutoLikerSettingsManager.cs
new file mode 100644
index 0000000..8c005c7
--- /dev/null
+++ b/AutoLikerCefSharpWpf/Helper/AutoLikerSettingsManager.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Diagnostics;
+using System.Windows.Controls;
+
+namespace AutoLikerCefSharpWpf.Helper
+{
+ internal class AutoLikerSettingsManager
+ {
+ private MainWindow main;
+
+ public AutoLikerSettingsManager(MainWindow win) {
+ this.main = win;
+ this.InitializeSettings();
+ }
+
+ private void InitializeSettings()
+ {
+ main.txtHashTag.Text = Properties.Settings.Default.Instagram_Hashtag;
+ main.txtDelayRestartMin.Text = Properties.Settings.Default.DelayRestartMin.ToString();
+ main.txtDelayRestartMax.Text = Properties.Settings.Default.DelayRestartMax.ToString();
+ main.txtMaxLikesMin.Text = Properties.Settings.Default.LikesMin.ToString();
+ main.txtMaxLikesMax.Text = Properties.Settings.Default.LikesMax.ToString();
+ main.txtDelayMin.Text = Properties.Settings.Default.DelayMin.ToString();
+ main.txtDelayMax.Text = Properties.Settings.Default.DelayMax.ToString();
+ this.ToggleSettingsSaveButton(false);
+
+ // assign handlers
+ main.txtHashTag.TextChanged += Al_Settings_TextChanged;
+ main.txtDelayRestartMin.TextChanged += Al_Settings_TextChanged;
+ main.txtDelayRestartMax.TextChanged += Al_Settings_TextChanged;
+ main.txtMaxLikesMin.TextChanged += Al_Settings_TextChanged;
+ main.txtMaxLikesMax.TextChanged += Al_Settings_TextChanged;
+ main.txtDelayMin.TextChanged += Al_Settings_TextChanged;
+ main.txtDelayMax.TextChanged += Al_Settings_TextChanged;
+ }
+
+ private void Al_Settings_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
+ {
+ TextBox tb = (TextBox)sender;
+ Debug.WriteLine("Setting changed: " + tb.Name + " = " + tb.Text);
+ this.ToggleSettingsSaveButton(true);
+ }
+
+ private void ToggleSettingsSaveButton(bool enable)
+ {
+ if (enable)
+ {
+ main.btnSaveSettings.IsEnabled = true;
+ }
+ else
+ {
+ main.btnSaveSettings.IsEnabled = false;
+ }
+ }
+
+ public void AutoTagSettingsSave()
+ {
+ int.TryParse(main.txtDelayRestartMin.Text, out int delayRestartMin);
+ int.TryParse(main.txtDelayRestartMax.Text, out int delayRestartMax);
+ int.TryParse(main.txtMaxLikesMin.Text, out int likesMin);
+ int.TryParse(main.txtMaxLikesMax.Text, out int likesMax);
+ int.TryParse(main.txtDelayMin.Text, out int delayMin);
+ int.TryParse(main.txtDelayMax.Text, out int delayMax);
+
+ Properties.Settings.Default.Instagram_Hashtag = main.txtHashTag.Text;
+ Properties.Settings.Default.DelayRestartMin = delayRestartMin;
+ Properties.Settings.Default.DelayRestartMax = delayRestartMax;
+ Properties.Settings.Default.LikesMin = likesMin;
+ Properties.Settings.Default.LikesMax = likesMax;
+ Properties.Settings.Default.DelayMin = delayMin;
+ Properties.Settings.Default.DelayMax = delayMax;
+
+ Properties.Settings.Default.Save();
+
+ main.LogMessage("Settings saved: " + DateTime.Now);
+
+ ToggleSettingsSaveButton(false);
+ }
+ }
+}
diff --git a/AutoLikerCefSharpWpf/Helper/JavaScriptBoundObject.cs b/AutoLikerCefSharpWpf/Helper/JavaScriptBoundObject.cs
new file mode 100644
index 0000000..e526e1b
--- /dev/null
+++ b/AutoLikerCefSharpWpf/Helper/JavaScriptBoundObject.cs
@@ -0,0 +1,79 @@
+using CefSharp;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace AutoLikerCefSharpWpf.Helper
+{
+ internal class JavaScriptBoundObject
+ {
+ private MainWindow Main;
+
+ public JavaScriptBoundObject(MainWindow win)
+ {
+ this.Main = win;
+ }
+
+ public void SingleLeftClick(int x, int y)
+ {
+ Debug.WriteLine("SingleLeftClick: x = " + x + " ; y = " + y);
+ MouseMoveEvent(x, y); // first move mouse to button
+ this.Main.Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.None);
+ System.Threading.Thread.Sleep(100);
+ this.Main.Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None);
+ }
+
+ public void DoubleLeftClick(int x, int y)
+ {
+ Debug.WriteLine("DoubleLeftClick: x = " + x + " ; y = " + y);
+ this.Main.Browser.GetBrowserHost().SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.LeftMouseButton);
+ this.Main.Browser.GetBrowserHost().SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None);
+ this.Main.Browser.GetBrowserHost().SendMouseClickEvent(x, y, MouseButtonType.Left, false, 2, CefEventFlags.LeftMouseButton);
+ this.Main.Browser.GetBrowserHost().SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None);
+ }
+
+ public void SingleRightClick(int x, int y)
+ {
+ Debug.WriteLine("SingleRightClick: x = " + x + " ; y = " + y);
+ this.Main.Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Right, false, 1, CefEventFlags.None);
+ System.Threading.Thread.Sleep(100);
+ this.Main.Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Right, true, 1, CefEventFlags.None);
+ }
+
+ public void MouseMoveEvent(int x, int y)
+ {
+ Debug.WriteLine("MouseMoveEvent: x = " + x + " ; y = " + y);
+ this.Main.Browser.GetBrowser().GetHost().SendMouseMoveEvent(x, y, false, CefEventFlags.None);
+ Thread.Sleep(50);
+ }
+
+ public void MouseScrollEvent(int mouseX, int mouseY, int scrollX, int scrollY)
+ {
+ Debug.WriteLine($"MouseScrollEvent: mouseX={mouseX}, mouseY={mouseY}, scrollX={scrollX}, scrollY={scrollY}");
+ this.Main.Browser.GetBrowser().GetHost().SendMouseWheelEvent(mouseX, mouseY, scrollX, scrollY, CefEventFlags.None);
+ Thread.Sleep(300);
+ }
+
+ public void KeyEscape()
+ {
+ KeyEvent k = new KeyEvent();
+ k.WindowsKeyCode = (int)Key.Escape;
+ this.Main.Browser.GetBrowser().GetHost().SendKeyEvent(k);
+ }
+
+ public void LogMessage(string msg)
+ {
+ this.Main.LogMessage(msg);
+ }
+
+ public void RestartProcess()
+ {
+ //this.Main.LoadInstragramTag();
+ }
+ }
+}
diff --git a/AutoLikerCefSharpWpf/Helper/JavaScriptProcessor.cs b/AutoLikerCefSharpWpf/Helper/JavaScriptProcessor.cs
new file mode 100644
index 0000000..5b35d25
--- /dev/null
+++ b/AutoLikerCefSharpWpf/Helper/JavaScriptProcessor.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+namespace AutoLikerCefSharpWpf.Helper
+{
+ internal class JavaScriptProcessor
+ {
+ private const string autoTagJavaScriptFilename = "autotag_injection.js";
+ private const string assetsNamespace = "AutoLikerCefSharpWpf.Assets.";
+
+ public static string PopulateJavaScriptFile(string tag, string posts, string cursor, string maxLikes, string delayPerLikeMin, string delayPerLikeMax)
+ {
+ string contents = ReturnJavaScriptFromFile(autoTagJavaScriptFilename);
+
+ if (contents != null)
+ {
+ contents = contents.Replace("{tag}", tag);
+ contents = contents.Replace("{posts}", posts);
+ contents = contents.Replace("{maxLikes}", maxLikes);
+ contents = contents.Replace("{delayPerLikeMin}", delayPerLikeMin);
+ contents = contents.Replace("{delayPerLikeMax}", delayPerLikeMax);
+ contents = contents.Replace("{cursor}", cursor);
+ }
+
+ return contents;
+ }
+
+ ///
+ /// Load a JS file from the filesystem
+ ///
+ /// Make sure that it is set to "Build Action" = "Embedded Resource"
+ ///
+ ///
+ ///
+ public static string ReturnJavaScriptFromFile(string filename)
+ {
+ string readContents = null;
+ var assembly = Assembly.GetExecutingAssembly();
+ try
+ {
+ if (filename == null)
+ {
+ filename = autoTagJavaScriptFilename;
+ }
+
+ var resourceName = assetsNamespace + filename;
+
+ Debug.WriteLine(" :: get resource = " + resourceName);
+
+ using (Stream stream = assembly.GetManifestResourceStream(resourceName))
+ using (StreamReader reader = new StreamReader(stream))
+ {
+ readContents = reader.ReadToEnd();
+ }
+ }
+ catch (Exception error)
+ {
+ Debug.WriteLine("Exception: " + error.Message);
+ }
+ return readContents;
+ }
+ }
+}
diff --git a/AutoLikerCefSharpWpf/MainWindow.xaml b/AutoLikerCefSharpWpf/MainWindow.xaml
index 8c51f31..7111000 100644
--- a/AutoLikerCefSharpWpf/MainWindow.xaml
+++ b/AutoLikerCefSharpWpf/MainWindow.xaml
@@ -7,48 +7,111 @@
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
Title="{Binding Path=Title, ElementName=Browser, Converter={StaticResource TitleConverter}}"
FocusManager.FocusedElement="{Binding ElementName=Browser}"
- WindowState="Maximized">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Chromium: , CEF: , CefSharp: , Environment:
-
-
-
-
+
+
+
+
+
+
diff --git a/AutoLikerCefSharpWpf/MainWindow.xaml.cs b/AutoLikerCefSharpWpf/MainWindow.xaml.cs
index a173531..7d2ba95 100644
--- a/AutoLikerCefSharpWpf/MainWindow.xaml.cs
+++ b/AutoLikerCefSharpWpf/MainWindow.xaml.cs
@@ -1,5 +1,8 @@
-using System;
+using AutoLikerCefSharpWpf.Helper;
+using CefSharp;
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -20,9 +23,188 @@ namespace AutoLikerCefSharpWpf
///
public partial class MainWindow : Window
{
+ private const string DefaultUrlForAddedTabs = "https://www.instagram.com/";
+ public string AutoLikerVersion { get; set; }
+ private AutoLikerSettingsManager _alsm;
public MainWindow()
{
InitializeComponent();
+
+ // version
+ this.AutoLikerVersion = "v2.0.0-20230912";
+ this.DataContext = this;
+ // manage settings in UI
+ this._alsm = new AutoLikerSettingsManager(this);
+
+ // Mouse Events
+ Browser.MouseMove += (sender, args) =>
+ {
+ Point position = Mouse.GetPosition(Browser);
+ this.txtMouseX.Text = Convert.ToString(Math.Floor(position.X));
+ this.txtMouseY.Text = Convert.ToString(Math.Floor(position.Y));
+ };
+
+ Browser.JavascriptObjectRepository.ResolveObject += (sender, e) =>
+ {
+ var repo = e.ObjectRepository;
+ if (e.ObjectName == "boundAsync")
+ {
+ BindingOptions bindingOptions = null; //Binding options is an optional param, defaults to null
+ bindingOptions = BindingOptions.DefaultBinder; //Use the default binder to serialize values into complex objects
+ repo.Register("boundAsync", new JavaScriptBoundObject(this), isAsync: true, options: bindingOptions);
+ }
+ };
+
+ Browser.JavascriptObjectRepository.ObjectBoundInJavascript += (sender, e) =>
+ {
+ var name = e.ObjectName;
+ Debug.WriteLine($"Object {e.ObjectName} was bound successfully.");
+ };
+
+ //Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)
+ Browser.LoadingStateChanged += (sender, args) =>
+ {
+ //Wait for the Page to finish loading
+ if (args.IsLoading == false)
+ {
+ //Browser.ExecuteScriptAsync("alert('All Resources Have Loaded');");
+ }
+ };
+
+ //Wait for the MainFrame to finish loading
+ Browser.FrameLoadEnd += (sender, args) =>
+ {
+ //Wait for the MainFrame to finish loading
+ if (args.Frame.IsMain)
+ {
+ if (args.Frame.Url.Contains("instagram.com/") && args.Frame.Url.Contains("#al"))
+ {
+ // Bind CEF object
+ string script = @"(async function()
+ {
+ await CefSharp.BindObjectAsync(""boundAsync"");
+
+ //The default is to camel case method names (the first letter of the method name is changed to lowercase)
+ boundAsync.logMessage(""This is a boundAsync test"");
+ console.log('boundAsync worked!');
+ })();";
+ args.Frame.ExecuteJavaScriptAsync(script);
+
+ // Inject JQuery
+ string jq = JavaScriptProcessor.ReturnJavaScriptFromFile("jquery-3.7.1.min.js");
+ args.Frame.ExecuteJavaScriptAsync(jq);
+
+ // Inject AutoLiker class
+ string aljs = JavaScriptProcessor.ReturnJavaScriptFromFile("autotag_injection_min.js");
+ args.Frame.ExecuteJavaScriptAsync(aljs);
+
+ this.Dispatcher.Invoke(() =>
+ {
+ // Execute script
+ string alStartScript = $@"(function()
+ {{
+ if (typeof jQuery == 'undefined') {{
+ console.log('Sorry, but jQuery wasn\'t able to load');
+ }} else {{
+ jQuery.noConflict();
+ console.log('This page is now jQuerified with v' + jQuery.fn.jquery);
+
+ jQuery(document).ready(function () {{
+ requestAnimationFrame(() => {{
+ queueMicrotask(() => {{
+ console.log('finished painting');
+
+ al=new alObject();
+ al.initializeSettings('{this.txtHashTag.Text}',
+ {this.txtMaxLikesMin.Text},
+ {this.txtMaxLikesMax.Text},
+ {this.txtDelayMin.Text},
+ {this.txtDelayMax.Text},
+ {this.txtDelayRestartMin.Text},
+ {this.txtDelayRestartMax.Text});
+ al.instagramStartClickProcess();
+ }});
+ }});
+ }});
+ }}
+ }})();";
+ args.Frame.ExecuteJavaScriptAsync(alStartScript);
+ });
+ }
+ }
+ };
+ }
+
+ private void Button_DevTools(object sender, RoutedEventArgs e)
+ {
+ Browser.ShowDevTools();
+ }
+
+ private void BtnStart_Click(object sender, RoutedEventArgs e)
+ {
+ Debug.WriteLine("==== BtnStart_Click ====");
+ this.LoadInstragramTag();
+ }
+
+ private void BtnStop_Click(object sender, RoutedEventArgs e)
+ {
+ Debug.WriteLine("==== BtnStop_Click ====");
+ this.Dispatcher.Invoke(() =>
+ {
+ Debug.WriteLine("*** STOPPING ***");
+ this.LogMessage("Stopping Auto Liking");
+ // reload browser
+ this.Browser.LoadUrl(DefaultUrlForAddedTabs);
+ //this.txtLog.IsReadOnly = false;
+ });
+ }
+
+ private void BtnSaveSettings_Click(object sender, RoutedEventArgs e)
+ {
+ Debug.WriteLine("==== BtnSaveSettings_Click ====");
+ this._alsm.AutoTagSettingsSave();
+ }
+
+ public void LoadInstragramTag()
+ {
+ Debug.WriteLine("==== LoadInstragramTag ====");
+ this.Dispatcher.Invoke(() =>
+ {
+ this.txtLog.Clear();
+ // get hashtag
+ string hashtag = this.txtHashTag.Text;
+ // check if multiple hastags
+ if (hashtag.Contains(","))
+ {
+ string[] hashtags = hashtag.Split(',');
+ int hashtags_length = hashtags.Length;
+ Debug.WriteLine(" - hashtags_length = " + hashtags_length);
+ Random rnd = new Random();
+ int hashtag_index = rnd.Next(hashtags_length);
+ Debug.WriteLine(" - hashtag_index = " + hashtag_index);
+ hashtag = hashtags.GetValue(hashtag_index).ToString().Trim();
+ }
+ this.LogMessage("Load Instagram Tag: " + hashtag);
+ // create URL
+ string URL = "https://www.instagram.com/explore/tags/" + hashtag + "/#al";
+ // reload browser
+ //this.browser.Address = URL;
+ this.Browser.Load(URL);
+ });
+ }
+
+ ///
+ /// Log message in UI text box
+ ///
+ /// String message
+ public void LogMessage(string msg)
+ {
+ this.Dispatcher.Invoke(() =>
+ {
+ Debug.WriteLine(msg);
+ this.txtLog.AppendText(msg + Environment.NewLine);
+ this.txtLog.ScrollToEnd();
+ });
}
}
}
diff --git a/AutoLikerCefSharpWpf/Properties/Settings.Designer.cs b/AutoLikerCefSharpWpf/Properties/Settings.Designer.cs
index ac3e0f3..0c296ff 100644
--- a/AutoLikerCefSharpWpf/Properties/Settings.Designer.cs
+++ b/AutoLikerCefSharpWpf/Properties/Settings.Designer.cs
@@ -8,23 +8,103 @@
//
//------------------------------------------------------------------------------
-namespace AutoLikerCefSharpWpf.Properties
-{
-
-
+namespace AutoLikerCefSharpWpf.Properties {
+
+
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
- {
-
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default
- {
- get
- {
+
+ public static Settings Default {
+ get {
return defaultInstance;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("travelphotography,familyphotographer")]
+ public string Instagram_Hashtag {
+ get {
+ return ((string)(this["Instagram_Hashtag"]));
+ }
+ set {
+ this["Instagram_Hashtag"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("45")]
+ public int DelayRestartMin {
+ get {
+ return ((int)(this["DelayRestartMin"]));
+ }
+ set {
+ this["DelayRestartMin"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("60")]
+ public int DelayRestartMax {
+ get {
+ return ((int)(this["DelayRestartMax"]));
+ }
+ set {
+ this["DelayRestartMax"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("10")]
+ public int LikesMin {
+ get {
+ return ((int)(this["LikesMin"]));
+ }
+ set {
+ this["LikesMin"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("25")]
+ public int LikesMax {
+ get {
+ return ((int)(this["LikesMax"]));
+ }
+ set {
+ this["LikesMax"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("5")]
+ public int DelayMin {
+ get {
+ return ((int)(this["DelayMin"]));
+ }
+ set {
+ this["DelayMin"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("15")]
+ public int DelayMax {
+ get {
+ return ((int)(this["DelayMax"]));
+ }
+ set {
+ this["DelayMax"] = value;
+ }
+ }
}
}
diff --git a/AutoLikerCefSharpWpf/Properties/Settings.settings b/AutoLikerCefSharpWpf/Properties/Settings.settings
index 033d7a5..7e44353 100644
--- a/AutoLikerCefSharpWpf/Properties/Settings.settings
+++ b/AutoLikerCefSharpWpf/Properties/Settings.settings
@@ -1,7 +1,27 @@
-
-
-
-
-
+
+
+
+
+ travelphotography,familyphotographer
+
+
+ 45
+
+
+ 60
+
+
+ 10
+
+
+ 25
+
+
+ 5
+
+
+ 15
+
+
\ No newline at end of file
diff --git a/AutoLikerCefSharpWpf/Settings.cs b/AutoLikerCefSharpWpf/Settings.cs
new file mode 100644
index 0000000..a89fd0b
--- /dev/null
+++ b/AutoLikerCefSharpWpf/Settings.cs
@@ -0,0 +1,28 @@
+namespace AutoLikerCefSharpWpf.Properties {
+
+
+ // This class allows you to handle specific events on the settings class:
+ // The SettingChanging event is raised before a setting's value is changed.
+ // The PropertyChanged event is raised after a setting's value is changed.
+ // The SettingsLoaded event is raised after the setting values are loaded.
+ // The SettingsSaving event is raised before the setting values are saved.
+ internal sealed partial class Settings {
+
+ public Settings() {
+ // // To add event handlers for saving and changing settings, uncomment the lines below:
+ //
+ // this.SettingChanging += this.SettingChangingEventHandler;
+ //
+ // this.SettingsSaving += this.SettingsSavingEventHandler;
+ //
+ }
+
+ private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
+ // Add code to handle the SettingChangingEvent event here.
+ }
+
+ private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
+ // Add code to handle the SettingsSaving event here.
+ }
+ }
+}