Migrated to new baseline

This commit is contained in:
Jack 2023-09-12 18:04:51 -04:00
parent 84db9660f1
commit c742979250
13 changed files with 998 additions and 83 deletions

View File

@ -1,6 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="AutoLikerCefSharpWpf.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<userSettings>
<AutoLikerCefSharpWpf.Properties.Settings>
<setting name="Instagram_Hashtag" serializeAs="String">
<value>travelphotography,familyphotographer</value>
</setting>
<setting name="DelayRestartMin" serializeAs="String">
<value>45</value>
</setting>
<setting name="DelayRestartMax" serializeAs="String">
<value>60</value>
</setting>
<setting name="LikesMin" serializeAs="String">
<value>10</value>
</setting>
<setting name="LikesMax" serializeAs="String">
<value>25</value>
</setting>
<setting name="DelayMin" serializeAs="String">
<value>5</value>
</setting>
<setting name="DelayMax" serializeAs="String">
<value>15</value>
</setting>
</AutoLikerCefSharpWpf.Properties.Settings>
</userSettings>
</configuration>

View File

@ -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;
}

File diff suppressed because one or more lines are too long

View File

@ -115,6 +115,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Helper\AutoLikerSettingsManager.cs" />
<Compile Include="Helper\JavaScriptBoundObject.cs" />
<Compile Include="Helper\JavaScriptProcessor.cs" />
<Compile Include="Settings.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -177,6 +181,10 @@
<ItemGroup>
<Resource Include="Resources\autoliker-512.ico" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\autotag_injection.js" />
<EmbeddedResource Include="Assets\autotag_injection_min.js" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
/// <summary>
/// Load a JS file from the filesystem
///
/// Make sure that it is set to "Build Action" = "Embedded Resource"
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
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;
}
}
}

View File

@ -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">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="2,5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="2,5" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="Back" Command="{Binding WebBrowser.BackCommand, ElementName=Browser}" Width="50"/>
<Button Content="Forward" Command="{Binding WebBrowser.ForwardCommand, ElementName=Browser}" Grid.Column="1" Width="60"/>
<TextBox x:Name="txtBoxAddress" Text="{Binding Address, ElementName=Browser, FallbackValue=www.google.com}" Grid.Column="2" FontSize="12" BorderBrush="Gray" BorderThickness="1">
<behaviors:Interaction.Behaviors>
<behaviours:TextBoxBindingUpdateOnEnterBehaviour />
</behaviors:Interaction.Behaviors>
</TextBox>
<Button Content="Print..." Command="{Binding WebBrowser.PrintCommand, ElementName=Browser}" Grid.Column="3" Width="50" />
<Button Content="View source" Command="{Binding WebBrowser.ViewSourceCommand, ElementName=Browser}" Grid.Column="4" Width="75" />
</Grid>
<Border Grid.Row="1" BorderBrush="Gray" BorderThickness="0,1">
<wpf:ChromiumWebBrowser x:Name="Browser"
WindowState="Maximized"
x:Name="AutoLikerWindow">
<DockPanel>
<DockPanel DockPanel.Dock="Left" Width="350px" Background="WhiteSmoke">
<Grid DockPanel.Dock="Top" Margin="5 5 5 5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Hashtags&#10;- don't include #&#10;- comma-separated" x:Name="lblHashTag" />
<Label Grid.Row="1" Grid.Column="0" Content="Maximum likes per page load" x:Name="lblMaxLikes" />
<Label Grid.Row="2" Grid.Column="0" Content="Delay range between likes (sec)" x:Name="lblDelay" />
<Label Grid.Row="3" Grid.Column="0" Content="Delay before reloading (min)" x:Name="lblDelayRestart" />
<TextBox Grid.Column="1" Grid.Row="0" Margin="3" Height="50px" TextWrapping="Wrap" x:Name="txtHashTag"/>
<StackPanel Grid.Column="1" Grid.Row="1" Margin="3" HorizontalAlignment="Left" Orientation="Horizontal">
<TextBox Width="40" x:Name="txtMaxLikesMin" />
<Label Content="-" />
<TextBox Width="40" x:Name="txtMaxLikesMax" />
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="2" Margin="3" HorizontalAlignment="Left" Orientation="Horizontal">
<TextBox Width="40" x:Name="txtDelayMin" />
<Label Content="-" />
<TextBox Width="40" x:Name="txtDelayMax" />
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="3" Margin="3" HorizontalAlignment="Left" Orientation="Horizontal">
<TextBox Width="40" x:Name="txtDelayRestartMin" />
<Label Content="-" />
<TextBox Width="40" x:Name="txtDelayRestartMax" />
</StackPanel>
<Button Grid.Column="1" Grid.Row="4" HorizontalAlignment="Left" MinWidth="80" Margin="3" Content="Save" x:Name="btnSaveSettings" Click="BtnSaveSettings_Click"/>
</Grid>
<StackPanel DockPanel.Dock="Top" HorizontalAlignment="Left" Orientation="Horizontal" Margin="0 5">
<Button x:Name="btnStart" Height="35" Width="40" Content="Start" Margin="5 0 0 0" Click="BtnStart_Click"/>
<Button x:Name="btnStop" Height="35" Width="40" Content="Stop" Margin="5 0 5 0" Click="BtnStop_Click"/>
</StackPanel>
<StackPanel DockPanel.Dock="Top" HorizontalAlignment="Left" Orientation="Horizontal">
<Label Content="MouseX:" />
<TextBox Margin="1" Width="75" x:Name="txtMouseX"/>
<Label Content="MouseY:" />
<TextBox Margin="1" Width="75" x:Name="txtMouseY"/>
</StackPanel>
<Grid DockPanel.Dock="Top" HorizontalAlignment="Stretch" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="24px" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0" x:Name="txtLog" TextWrapping="Wrap" IsReadOnly="True"
VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>
<Label Grid.Row="1" x:Name="lblAppVersion" HorizontalContentAlignment="Left" Content="{Binding AutoLikerVersion, Mode=OneWay}"/>
</Grid>
</DockPanel>
<DockPanel DockPanel.Dock="Right" x:Name="browser_panel">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="2,5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="2,5" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="Back" Command="{Binding WebBrowser.BackCommand, ElementName=Browser}" Width="50"/>
<Button Content="Forward" Command="{Binding WebBrowser.ForwardCommand, ElementName=Browser}" Grid.Column="1" Width="60"/>
<TextBox x:Name="txtBoxAddress" Text="{Binding Address, ElementName=Browser, FallbackValue=www.google.com}" Grid.Column="2" FontSize="12" BorderBrush="Gray" BorderThickness="1">
<behaviors:Interaction.Behaviors>
<behaviours:TextBoxBindingUpdateOnEnterBehaviour />
</behaviors:Interaction.Behaviors>
</TextBox>
<Button Content="Print..." Command="{Binding WebBrowser.PrintCommand, ElementName=Browser}" Grid.Column="3" Width="50" />
<Button Content="DevTools" Click="Button_DevTools" Grid.Column="4" Width="60" />
</Grid>
<Border Grid.Row="1" BorderBrush="Gray" BorderThickness="0,1">
<wpf:ChromiumWebBrowser x:Name="Browser"
Address="https://www.google.com">
<behaviors:Interaction.Behaviors>
<behaviours:HoverLinkBehaviour x:Name="HoverLinkBehaviour"/>
</behaviors:Interaction.Behaviors>
</wpf:ChromiumWebBrowser>
</Border>
<ProgressBar IsIndeterminate="{Binding IsLoading, ElementName=Browser}"
<behaviors:Interaction.Behaviors>
<behaviours:HoverLinkBehaviour x:Name="HoverLinkBehaviour"/>
</behaviors:Interaction.Behaviors>
</wpf:ChromiumWebBrowser>
</Border>
<ProgressBar IsIndeterminate="{Binding IsLoading, ElementName=Browser}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Width="Auto"
@ -56,27 +119,29 @@
Height="2"
Visibility="{Binding IsLoading, ElementName=Browser, Converter={StaticResource BooleanToVisibilityConverter}}"
BorderThickness="0" />
<StatusBar Grid.Row="2" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Text="{Binding HoverLink, ElementName=HoverLinkBehaviour}" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="3" VerticalAlignment="Center">
<StatusBar Grid.Row="2" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Text="{Binding HoverLink, ElementName=HoverLinkBehaviour}" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="3" VerticalAlignment="Center">
Chromium: <Run Text="{Binding Source={x:Static cef:Cef.ChromiumVersion}, Mode=OneTime}" />, CEF: <Run Text="{Binding Source={x:Static cef:Cef.CefVersion}, Mode=OneTime}" />, CefSharp: <Run Text="{Binding Source={x:Static cef:Cef.CefSharpVersion}, Mode=OneTime}"/>, Environment: <Run Text="{Binding Converter={StaticResource EnvironmentConverter}, Mode=OneTime}"/>
</TextBlock>
</StatusBarItem>
</StatusBar>
</Grid>
</TextBlock>
</StatusBarItem>
</StatusBar>
</Grid>
</DockPanel>
</DockPanel>
</Window>

View File

@ -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
/// </summary>
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);
});
}
/// <summary>
/// Log message in UI text box
/// </summary>
/// <param name="msg">String message</param>
public void LogMessage(string msg)
{
this.Dispatcher.Invoke(() =>
{
Debug.WriteLine(msg);
this.txtLog.AppendText(msg + Environment.NewLine);
this.txtLog.ScrollToEnd();
});
}
}
}

View File

@ -8,23 +8,103 @@
// </auto-generated>
//------------------------------------------------------------------------------
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;
}
}
}
}

View File

@ -1,7 +1,27 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="AutoLikerCefSharpWpf.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="Instagram_Hashtag" Type="System.String" Scope="User">
<Value Profile="(Default)">travelphotography,familyphotographer</Value>
</Setting>
<Setting Name="DelayRestartMin" Type="System.Int32" Scope="User">
<Value Profile="(Default)">45</Value>
</Setting>
<Setting Name="DelayRestartMax" Type="System.Int32" Scope="User">
<Value Profile="(Default)">60</Value>
</Setting>
<Setting Name="LikesMin" Type="System.Int32" Scope="User">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="LikesMax" Type="System.Int32" Scope="User">
<Value Profile="(Default)">25</Value>
</Setting>
<Setting Name="DelayMin" Type="System.Int32" Scope="User">
<Value Profile="(Default)">5</Value>
</Setting>
<Setting Name="DelayMax" Type="System.Int32" Scope="User">
<Value Profile="(Default)">15</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -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.
}
}
}