├── master ├── docs ├── img │ ├── gui.PNG │ ├── gui2.PNG │ ├── gui3.PNG │ ├── gui4.PNG │ ├── gui5.PNG │ ├── submit.PNG │ ├── accounts.PNG │ ├── accounts2.PNG │ ├── accounts3.PNG │ ├── articles.PNG │ ├── articles2.PNG │ ├── articles3.PNG │ ├── articles4.PNG │ ├── articles5.PNG │ ├── articles6.PNG │ ├── articles7.PNG │ ├── indexers1.PNG │ ├── indexers2.PNG │ ├── indexers3.PNG │ ├── install.PNG │ ├── install2.PNG │ ├── install3.PNG │ ├── install4.PNG │ ├── install5.PNG │ ├── install6.PNG │ ├── submit2.PNG │ ├── submit3.PNG │ ├── submit4.PNG │ ├── submit5.PNG │ ├── submit6.PNG │ └── home-image.png ├── current-services.md ├── gui.md ├── readme.md ├── accounts.md ├── indexers.md ├── submit.md ├── install-cli.md └── articles.md ├── settings └── services.txt ├── .gitignore ├── license.md ├── indexers ├── backlinksindexer.coffee ├── backlinksindexer.js ├── indexification.coffee └── indexification.js ├── app ├── console-xtra.coffee ├── console-xtra.js ├── imports.coffee ├── spinner.coffee ├── spinner.js └── imports.js ├── services ├── blogdotcom.coffee ├── blogdotcom.js ├── wordpress.coffee └── wordpress.js ├── README.md ├── open-submitter.coffee └── open-submitter.js /master: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/img/gui.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/gui.PNG -------------------------------------------------------------------------------- /docs/img/gui2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/gui2.PNG -------------------------------------------------------------------------------- /docs/img/gui3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/gui3.PNG -------------------------------------------------------------------------------- /docs/img/gui4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/gui4.PNG -------------------------------------------------------------------------------- /docs/img/gui5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/gui5.PNG -------------------------------------------------------------------------------- /docs/img/submit.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/submit.PNG -------------------------------------------------------------------------------- /docs/img/accounts.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/accounts.PNG -------------------------------------------------------------------------------- /docs/img/accounts2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/accounts2.PNG -------------------------------------------------------------------------------- /docs/img/accounts3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/accounts3.PNG -------------------------------------------------------------------------------- /docs/img/articles.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles.PNG -------------------------------------------------------------------------------- /docs/img/articles2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles2.PNG -------------------------------------------------------------------------------- /docs/img/articles3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles3.PNG -------------------------------------------------------------------------------- /docs/img/articles4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles4.PNG -------------------------------------------------------------------------------- /docs/img/articles5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles5.PNG -------------------------------------------------------------------------------- /docs/img/articles6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles6.PNG -------------------------------------------------------------------------------- /docs/img/articles7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/articles7.PNG -------------------------------------------------------------------------------- /docs/img/indexers1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/indexers1.PNG -------------------------------------------------------------------------------- /docs/img/indexers2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/indexers2.PNG -------------------------------------------------------------------------------- /docs/img/indexers3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/indexers3.PNG -------------------------------------------------------------------------------- /docs/img/install.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/install.PNG -------------------------------------------------------------------------------- /docs/img/install2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/install2.PNG -------------------------------------------------------------------------------- /docs/img/install3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/install3.PNG -------------------------------------------------------------------------------- /docs/img/install4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/install4.PNG -------------------------------------------------------------------------------- /docs/img/install5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/install5.PNG -------------------------------------------------------------------------------- /docs/img/install6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/install6.PNG -------------------------------------------------------------------------------- /docs/img/submit2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/submit2.PNG -------------------------------------------------------------------------------- /docs/img/submit3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/submit3.PNG -------------------------------------------------------------------------------- /docs/img/submit4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/submit4.PNG -------------------------------------------------------------------------------- /docs/img/submit5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/submit5.PNG -------------------------------------------------------------------------------- /docs/img/submit6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/submit6.PNG -------------------------------------------------------------------------------- /docs/img/home-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BackSpaceTech/open-submitter/HEAD/docs/img/home-image.png -------------------------------------------------------------------------------- /settings/services.txt: -------------------------------------------------------------------------------- 1 | #name# 2 | wordpress 3 | #status# 4 | ok 5 | #name# 6 | blogdotcom 7 | #status# 8 | bad 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | node_modules/* 3 | accounts/* 4 | articles/* 5 | backlinks/* 6 | settings/indexers.txt 7 | capture/* 8 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Open Submitter is free and open source software licensed under the [GNU GPL v3][970c67c8] 2 | 3 | [970c67c8]: https://www.gnu.org/licenses/gpl-3.0.en.html "Open Submitter GNU GPL License" 4 | -------------------------------------------------------------------------------- /docs/current-services.md: -------------------------------------------------------------------------------- 1 | # Current Open Submitter Services List 2 | 3 | 4 | 5 | This list is updated when new services are created. Make sure you have Sibbel set up to notify of updates (see [set up page](install-cli.md) for more details). 6 | 7 | 8 | | Service ID | Service | Service Homepage | Reliability | Script Last Updated | 9 | |------------ |----------- |------------------ |------------- |--------------------- | 10 | | wordpress | WordPress | wordpress.com | Excellent | 19 July 2016 | 11 | | blog.com | Blog.com | blog.com | Poor | 19 July 2016 | 12 | 13 | 14 | 15 | 16 | 17 | [Documentation Home][c689026d] 18 | 19 | [c689026d]: readme.md "Open Submitter Documentation" 20 | -------------------------------------------------------------------------------- /indexers/backlinksindexer.coffee: -------------------------------------------------------------------------------- 1 | exports.name = 'backlinksindexer.com' 2 | exports.steps = [ 3 | { 4 | command: 'open' 5 | url: 'http://backlinksindexer.com/wp-login.php' 6 | confirm: '#user_login' 7 | } 8 | { 9 | command: 'login-indexer' 10 | form: '#loginform' 11 | username: '#user_login' 12 | password: '#user_pass' 13 | submit: false 14 | } 15 | { 16 | command: 'click' 17 | selector: '#wp-submit' 18 | confirmtxt: 'Log out' 19 | } 20 | { 21 | command: 'open' 22 | url: 'http://backlinksindexer.com/dashboard/' 23 | confirm: '#url-textarea' 24 | } 25 | { 26 | command: 'backlinks' 27 | selector: '#url-textarea' 28 | } 29 | { 30 | command: 'click' 31 | selector: '#submit_add' 32 | confirm: '.alert-success' 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /app/console-xtra.coffee: -------------------------------------------------------------------------------- 1 | exports.log = (msgColor, msg) -> 2 | colorsANSI = [ 3 | { 4 | text: 'black' 5 | code: '\x1b[30m' 6 | } 7 | { 8 | text: 'red' 9 | code: '\x1b[31m' 10 | } 11 | { 12 | text: 'green' 13 | code: '\x1b[32m' 14 | } 15 | { 16 | text: 'yellow' 17 | code: '\x1b[33m' 18 | } 19 | { 20 | text: 'blue' 21 | code: '\x1b[34m' 22 | } 23 | { 24 | text: 'magenta' 25 | code: '\x1b[35m' 26 | } 27 | { 28 | text: 'cyan' 29 | code: '\x1b[36m' 30 | } 31 | { 32 | text: 'white' 33 | code: '\x1b[37m' 34 | } 35 | ] 36 | colorCode = '' 37 | for i in [0...colorsANSI.length] 38 | if msgColor == colorsANSI[i].text 39 | colorCode = colorsANSI[i].code 40 | console.log colorCode, msg, '\x1b[0m' 41 | -------------------------------------------------------------------------------- /indexers/backlinksindexer.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | 4 | exports.name = 'backlinksindexer.com'; 5 | 6 | exports.steps = [ 7 | { 8 | command: 'open', 9 | url: 'http://backlinksindexer.com/wp-login.php', 10 | confirm: '#user_login' 11 | }, { 12 | command: 'login-indexer', 13 | form: '#loginform', 14 | username: '#user_login', 15 | password: '#user_pass', 16 | submit: false 17 | }, { 18 | command: 'click', 19 | selector: '#wp-submit', 20 | confirmtxt: 'Log out' 21 | }, { 22 | command: 'open', 23 | url: 'http://backlinksindexer.com/dashboard/', 24 | confirm: '#url-textarea' 25 | }, { 26 | command: 'backlinks', 27 | selector: '#url-textarea' 28 | }, { 29 | command: 'click', 30 | selector: '#submit_add', 31 | confirm: '.alert-success' 32 | } 33 | ]; 34 | 35 | }).call(this); 36 | -------------------------------------------------------------------------------- /indexers/indexification.coffee: -------------------------------------------------------------------------------- 1 | exports.name = 'indexification.com' 2 | exports.steps = [ 3 | { 4 | command: 'open' 5 | url: 'http://www.indexification.com/' 6 | confirm: '#button-login' 7 | } 8 | { 9 | command: 'click' 10 | selector: '#button-login' 11 | confirm: '#dialog-login' 12 | } 13 | { 14 | command: 'login-indexer' 15 | form: '#LoginForm' 16 | username: '#loginuser' 17 | password: '#loginpass' 18 | submit: false 19 | } 20 | { 21 | command: 'click' 22 | xpath: '(//button[@type="button"])[4]' 23 | } 24 | { 25 | command: 'wait' 26 | value: 5000 27 | } 28 | { 29 | command: 'open' 30 | url: 'http://www.indexification.com/members/addcampaign.php' 31 | confirm: '#links' 32 | } 33 | { 34 | command: 'backlinks' 35 | selector: '#links' 36 | } 37 | { 38 | command: 'click' 39 | selector: '#user-updateprofile' 40 | confirmtxt: 'Success!' 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /docs/gui.md: -------------------------------------------------------------------------------- 1 | # Open Submitter Graphical User Interface (GUI) 2 | 3 | The Graphical User Interface (GUI) simplifies the creation of article submission files and indexer setup files. 4 | 5 | ![](./img/gui.PNG) 6 | 7 | It can be download and installed from the [Chrome app store][db40ed37]. 8 | 9 | ## Create shortcut for app 10 | 11 | Navigate to your desktop in file explorer. Right click and select create shortcut. 12 | ![](./img/gui2.PNG) 13 | 14 | Paste the URL for the app: 15 | https://chrome.google.com/webstore/detail/open-submitter/pdhmmmkbclicklmfjpjbklkmoacdlolg 16 | 17 | 18 | 19 | ![](./img/gui3.PNG) 20 | 21 | Click Next 22 | 23 | Give the link the name Open Submitter 24 | 25 | ![](./img/gui4.PNG) 26 | 27 | Click Finish 28 | 29 | Check your desktop to find the link to the app. 30 | 31 | 32 | ![](./img/gui5.PNG) 33 | 34 | 35 | 36 | [Documentation Home][47774e43] 37 | 38 | [db40ed37]: https://chrome.google.com/webstore/detail/open-submitter/pdhmmmkbclicklmfjpjbklkmoacdlolg "Open Submitter App" 39 | [47774e43]: readme.md "Open Submitter Documentation" 40 | -------------------------------------------------------------------------------- /indexers/indexification.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | 4 | exports.name = 'indexification.com'; 5 | 6 | exports.steps = [ 7 | { 8 | command: 'open', 9 | url: 'http://www.indexification.com/', 10 | confirm: '#button-login' 11 | }, { 12 | command: 'click', 13 | selector: '#button-login', 14 | confirm: '#dialog-login' 15 | }, { 16 | command: 'login-indexer', 17 | form: '#LoginForm', 18 | username: '#loginuser', 19 | password: '#loginpass', 20 | submit: false 21 | }, { 22 | command: 'click', 23 | xpath: '(//button[@type="button"])[4]' 24 | }, { 25 | command: 'wait', 26 | value: 5000 27 | }, { 28 | command: 'open', 29 | url: 'http://www.indexification.com/members/addcampaign.php', 30 | confirm: '#links' 31 | }, { 32 | command: 'backlinks', 33 | selector: '#links' 34 | }, { 35 | command: 'click', 36 | selector: '#user-updateprofile', 37 | confirmtxt: 'Success!' 38 | } 39 | ]; 40 | 41 | }).call(this); 42 | -------------------------------------------------------------------------------- /app/console-xtra.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | 4 | exports.log = function(msgColor, msg) { 5 | var colorCode, colorsANSI, i, _i, _ref; 6 | colorsANSI = [ 7 | { 8 | text: 'black', 9 | code: '\x1b[30m' 10 | }, { 11 | text: 'red', 12 | code: '\x1b[31m' 13 | }, { 14 | text: 'green', 15 | code: '\x1b[32m' 16 | }, { 17 | text: 'yellow', 18 | code: '\x1b[33m' 19 | }, { 20 | text: 'blue', 21 | code: '\x1b[34m' 22 | }, { 23 | text: 'magenta', 24 | code: '\x1b[35m' 25 | }, { 26 | text: 'cyan', 27 | code: '\x1b[36m' 28 | }, { 29 | text: 'white', 30 | code: '\x1b[37m' 31 | } 32 | ]; 33 | colorCode = ''; 34 | for (i = _i = 0, _ref = colorsANSI.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { 35 | if (msgColor === colorsANSI[i].text) { 36 | colorCode = colorsANSI[i].code; 37 | } 38 | } 39 | return console.log(colorCode, msg, '\x1b[0m'); 40 | }; 41 | 42 | }).call(this); 43 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Open Submitter Documentation 2 | 3 | ## Contents: 4 | - [Set Up Open Submitter][f159407d] 5 | - [Accounts][f3cb5827] 6 | - [Graphical User Interface (GUI)][90d887fa] 7 | - [Articles][305c1ef4] 8 | - [Indexers][a2eb8215] 9 | - [Submitting to Services][0c9539fb] 10 | - Creating New Services 11 | 12 | [489d3415]: prerequisites.md "Open Submitter Prerequisites" 13 | [f159407d]: install-cli.md "Open Submitter CLI Install" 14 | [f3cb5827]: accounts.md "Open Submitter Documentation - Accounts" 15 | [90d887fa]: gui.md "Open Submitter Graphical User Interface (GUI)" 16 | [305c1ef4]: articles.md "Open Submitter Article Creation" 17 | [a2eb8215]: indexers.md "Open Submitter Indexers" 18 | [0c9539fb]: submit.md "Open Submitter Submitting to Services" 19 | 20 | 21 | ## More tutorials and information at the [Open Submitter Home Page][76d3e968] 22 | 23 | Free and open source software licensed under the [GNU GPL v3][efb18a06]. Copyright [BackSpace Technology][3ed15560]. 24 | 25 | [76d3e968]: http://opensubmitter.org/ "Free and open source backlinking software app." 26 | [efb18a06]: https://www.gnu.org/licenses/gpl-3.0.en.html "Open Submitter GNU GPL License" 27 | [3ed15560]: https://backspace.academy/ "BackSpace Academy" 28 | -------------------------------------------------------------------------------- /services/blogdotcom.coffee: -------------------------------------------------------------------------------- 1 | exports.name = 'blog.com' 2 | exports.steps = [ 3 | { 4 | command: 'create' 5 | micro: false 6 | noHTML: false 7 | } 8 | { 9 | command: 'open' 10 | url: 'http://blog.com/' 11 | confirm: '#loginform' 12 | } 13 | { 14 | command: 'login' 15 | form: '#loginform' 16 | username: '#user_login' 17 | password: '#user_pass' 18 | submit: true 19 | confirm: '#site-title' 20 | } 21 | { 22 | command: 'open-site' 23 | begin: 'http://' 24 | end: '.blog.com/wp-admin/post-new.php' 25 | confirm: '#post-body' 26 | } 27 | { 28 | command: 'click' 29 | selector: '#edButtonHTML' 30 | } 31 | { 32 | command: 'title' 33 | selector: 'input#title' 34 | } 35 | { 36 | command: 'wait' 37 | value: 1000 38 | } 39 | { 40 | command: 'body' 41 | selector: 'textarea#content' 42 | } 43 | { 44 | command: 'wait' 45 | value: 1000 46 | } 47 | { 48 | command: 'click' 49 | selector: 'input#publish' 50 | confirmtxt: 'Post published. ' 51 | } 52 | { 53 | command: 'wait' 54 | value: 1000 55 | } 56 | { 57 | command: 'save-href' 58 | selector: '#message p a' 59 | } 60 | { 61 | command: 'click' 62 | selector: 'a[title="Sign Out"]' 63 | confirm: '#loginform' 64 | } 65 | ] 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Submitter 2 | SEO Spinning and Backlinking App 3 | 4 | ![](./docs/img/home-image.png) 5 | 6 | ## SEO Backlinking software: 7 | - Spins articles 8 | - Inserts backlinks 9 | - Inserts images from custom list in random locations 10 | - Submits spun articles to blogs, microblogs, social pages etc. 11 | - Saves backlink URL to file 12 | - Submits backlinks to indexing services 13 | - Additional services can be added through simple command steps 14 | 15 | ## Prerequisites 16 | - [NodeJS][ca1dffb7] v4.4.7 or greater 17 | - [PhantomJS][6997c770] v2.1 or greater 18 | - [CasperJS][476ee510] v1.1.1 or greater 19 | - [Cmder][9924c39d] (optional) 20 | - [The Best Spinner][67703f2d] (optional) 21 | 22 | [ca1dffb7]: http://nodejs.org/ "NodeJS" 23 | [6997c770]: http://phantomjs.org/ "PhantomJS" 24 | [476ee510]: http://casperjs.org/ "CasperJS" 25 | [9924c39d]: http://cmder.net/ "Cmder" 26 | [67703f2d]: http://paydotcom.net/r/95330/pcoady/27453918/ "The Best Spinner" 27 | 28 | 29 | ## More details in the [documentation][bd90079e] 30 | 31 | 32 | Open Submitter is free and open source software licensed under the [GNU GPL v3][471c7b4b]. Copyright [BackSpace Technology.][520d0698] 33 | 34 | [bd90079e]: https://github.com/BackSpaceTech/open-submitter/tree/master/docs "Open Submitter Documentation" 35 | [471c7b4b]: https://www.gnu.org/licenses/gpl-3.0.en.html "Open Submitter GNU GPL License" 36 | [520d0698]: https://backspace.academy/ "BackSpace Technology" 37 | -------------------------------------------------------------------------------- /services/blogdotcom.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | 4 | exports.name = 'blog.com'; 5 | 6 | exports.steps = [ 7 | { 8 | command: 'create', 9 | micro: false, 10 | noHTML: false 11 | }, { 12 | command: 'open', 13 | url: 'http://blog.com/', 14 | confirm: '#loginform' 15 | }, { 16 | command: 'login', 17 | form: '#loginform', 18 | username: '#user_login', 19 | password: '#user_pass', 20 | submit: true, 21 | confirm: '#site-title' 22 | }, { 23 | command: 'open-site', 24 | begin: 'http://', 25 | end: '.blog.com/wp-admin/post-new.php', 26 | confirm: '#post-body' 27 | }, { 28 | command: 'click', 29 | selector: '#edButtonHTML' 30 | }, { 31 | command: 'title', 32 | selector: 'input#title' 33 | }, { 34 | command: 'wait', 35 | value: 1000 36 | }, { 37 | command: 'body', 38 | selector: 'textarea#content' 39 | }, { 40 | command: 'wait', 41 | value: 1000 42 | }, { 43 | command: 'click', 44 | selector: 'input#publish', 45 | confirmtxt: 'Post published. ' 46 | }, { 47 | command: 'wait', 48 | value: 1000 49 | }, { 50 | command: 'save-href', 51 | selector: '#message p a' 52 | }, { 53 | command: 'click', 54 | selector: 'a[title="Sign Out"]', 55 | confirm: '#loginform' 56 | } 57 | ]; 58 | 59 | }).call(this); 60 | -------------------------------------------------------------------------------- /docs/accounts.md: -------------------------------------------------------------------------------- 1 | # Open Submitter Accounts 2 | 3 | Accounts are required for Open Submitter to login and submit your articles. 4 | 5 | ## Creating Accounts 6 | 7 | Each service (e.g. Wordpress) will have its own process for creating accounts. Normally only one account per email address can be created. Free emails can be created at mail.ru (use Google Chrome Translate to view in English). After your accounts are created you will need the login names (or email addresses if applicable), passwords and site names (if applicable). Try to create many accounts for each service. 8 | 9 | ## Creating Accounts List file 10 | 11 | Open Submitter will look for your acounts file in the accounts directory of the Open Subnmitter root directory. This does not exist so you need to create it first. Make sure the folder name is in lowercase. 12 | 13 | ![](./img/accounts2.PNG) 14 | 15 | Account lists need to be created in csv format. Open a spreadsheet application and create a new spreadsheet with the account details on each row in the following order: 16 | - service id (see [current available services][3f03f862]) 17 | - username 18 | - password 19 | - site name (if applicable) 20 | 21 | [3f03f862]: current-services.md "Open Submitter Current Available Services" 22 | 23 | ![](./img/accounts.PNG) 24 | 25 | Now save your file as csv type in the accounts folder. 26 | 27 | ![](./img/accounts3.PNG) 28 | 29 | 30 | 31 | [Documentation Home][03b4df1a] 32 | 33 | [03b4df1a]: readme.md "Open Submitter Documentation" 34 | -------------------------------------------------------------------------------- /services/wordpress.coffee: -------------------------------------------------------------------------------- 1 | exports.name = 'wordpress' 2 | exports.steps = [ 3 | { 4 | command: 'create' 5 | micro: false 6 | noHTML: false 7 | } 8 | { 9 | command: 'open' 10 | url: 'https://wordpress.com/wp-login.php' 11 | confirm: '#user_login' 12 | } 13 | { 14 | command: 'login' 15 | form: '#loginform' 16 | username: '#user_login' 17 | password: '#user_pass' 18 | submit: true 19 | confirm: 'a[data-tip-target="my-sites"]' 20 | } 21 | { 22 | command: 'open-site' 23 | begin: 'https://wordpress.com/post/' 24 | end: '' 25 | confirm: '#tinymce-1' 26 | } 27 | { 28 | command: 'click' 29 | selector: 'svg.gridicon.gridicons-create' 30 | } 31 | { 32 | command: 'wait' 33 | value: 1000 34 | } 35 | { 36 | command: 'title' 37 | selector: 'textarea.textarea-autosize.editor-title__input' 38 | } 39 | { 40 | command: 'click' 41 | selector: 'a[title="Edit the raw HTML code"]' 42 | } 43 | { 44 | command: 'wait' 45 | value: 1000 46 | } 47 | { 48 | command: 'body' 49 | selector: '#tinymce-1' 50 | } 51 | { 52 | command: 'click' 53 | xpath: '//*[text()[contains(.,"Publish")]]' 54 | confirm: '.is-success' 55 | } 56 | { 57 | command: 'save-href' 58 | selector: 'a.notice__action' 59 | } 60 | { 61 | command: 'click' 62 | selector: 'img[class="gravatar"]' 63 | confirm: 'button[title="Sign out of WordPress.com"]' 64 | } 65 | { 66 | command: 'click' 67 | selector: 'button[title="Sign out of WordPress.com"]' 68 | } 69 | { 70 | command: 'wait' 71 | value: 5000 72 | } 73 | ] 74 | -------------------------------------------------------------------------------- /services/wordpress.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | 4 | exports.name = 'wordpress'; 5 | 6 | exports.steps = [ 7 | { 8 | command: 'create', 9 | micro: false, 10 | noHTML: false 11 | }, { 12 | command: 'open', 13 | url: 'https://wordpress.com/wp-login.php', 14 | confirm: '#user_login' 15 | }, { 16 | command: 'login', 17 | form: '#loginform', 18 | username: '#user_login', 19 | password: '#user_pass', 20 | submit: true, 21 | confirm: 'a[data-tip-target="my-sites"]' 22 | }, { 23 | command: 'open-site', 24 | begin: 'https://wordpress.com/post/', 25 | end: '', 26 | confirm: '#tinymce-1' 27 | }, { 28 | command: 'click', 29 | selector: 'svg.gridicon.gridicons-create' 30 | }, { 31 | command: 'wait', 32 | value: 1000 33 | }, { 34 | command: 'title', 35 | selector: 'textarea.textarea-autosize.editor-title__input' 36 | }, { 37 | command: 'click', 38 | selector: 'a[title="Edit the raw HTML code"]' 39 | }, { 40 | command: 'wait', 41 | value: 1000 42 | }, { 43 | command: 'body', 44 | selector: '#tinymce-1' 45 | }, { 46 | command: 'click', 47 | xpath: '//*[text()[contains(.,"Publish")]]', 48 | confirm: '.is-success' 49 | }, { 50 | command: 'save-href', 51 | selector: 'a.notice__action' 52 | }, { 53 | command: 'click', 54 | selector: 'img[class="gravatar"]', 55 | confirm: 'button[title="Sign out of WordPress.com"]' 56 | }, { 57 | command: 'click', 58 | selector: 'button[title="Sign out of WordPress.com"]' 59 | }, { 60 | command: 'wait', 61 | value: 5000 62 | } 63 | ]; 64 | 65 | }).call(this); 66 | -------------------------------------------------------------------------------- /docs/indexers.md: -------------------------------------------------------------------------------- 1 | # Set Up Indexing Services 2 | 3 | 4 | An indexing service is required to drive search engines to your submitted articles. The techniques used vary but are generally backlink based or pinging based (poor quality) or a mix of both. Depending on the technique used by the service, results can vary. Some services can get links on to search engines only to have then drop off later. The ratio of new to lost links is a significant factor in search engine ranking. This may not be an issue if you are just getting paid to create new backlinks. 5 | 6 | 7 | [BacklinksIndexer.com][ace3719b] is recommended if your require high ranking on search engines. This service will provide high quality tier 1, 2 and 3 backlinks to your articles. This can be used to not only index your article backlinks, but you can also submit your main site URLs regularly to create further backlinks from various domains. This makes your SEO campaign look more natural to search engines. 8 | 9 | [Indexification.com][44bd53cf] is a low cost indexing service with good indexing rates at very low cost. This is a good service for SEO contractors that are getting paid to create links on a regular basis for clients. It is also a good option to use as a backup to a premium service when you run out of monthly credits. 10 | 11 | ## Create Indexers Configuration File 12 | 13 | 14 | When you have created your accounts with an indexing provider you can set up Open Submitter to automatically submit URLs to them. Open the GUI app and select "Set Up Indexers". 15 | 16 | ![](./img/indexers2.PNG) 17 | 18 | Enter your username and account for the service. Make sure you check "Automatically send backlinks to indexer". 19 | 20 | ![](./img/indexers1.PNG) 21 | 22 | Now save the file as indexers.txt to the settings folder. 23 | 24 | 25 | ![](./img/indexers3.PNG) 26 | 27 | 28 | 29 | [Documentation Home][3acc32de] 30 | 31 | [3acc32de]: readme.md "Open Submitter Documentation" 32 | 33 | 34 | [44bd53cf]: http://aff.innocoders.com/idevaffiliate.php?id=1640_2_3_1 "Indexification.com" 35 | 36 | 37 | 38 | [ace3719b]: http://jvz1.com/c/540185/31395 "BacklinksIndexer.com" 39 | -------------------------------------------------------------------------------- /docs/submit.md: -------------------------------------------------------------------------------- 1 | # Submitting to Services 2 | 3 | Once you have set up Open Submitter: 4 | - prequesite frameworks installed and tested 5 | - article submission file has been created and saved to the articles folder 6 | - accounts csv file created and saved to accounts folder 7 | - indexing service file created and saved to settings folder 8 | 9 | You can now start the submit service. 10 | 11 | ## Starting the Submit Service 12 | 13 | The submit service must be started through the Command Line Interface (CLI). Open a command console (we recommend using the free app [Cmder][35fd80d0] if you are using Windows) and navigate to the Open Submitter directory. 14 | 15 | ![](./img/submit.PNG) 16 | 17 | 18 | To start the service run the following casperjs command: 19 | - casperjs (the headless webkit service) 20 | - open-submitter.js (Open Submitter application) 21 | - the name of your accounts file without the file extension 22 | - the name of your article submission file without the file extension 23 | - the file name to store backlinks to without the file extension 24 | - number of submission loops. e.g. if you have 20 accounts per service you may want to submit 5 randomly per day. 25 | 26 | e.g. 27 | 28 | casperjs open-submitter.js accounts articles backlinks 5 29 | 30 | 31 | ![](./img/submit6.PNG) 32 | 33 | The submit service will now start submitting the article to the services. 34 | 35 | ![](./img/submit3.PNG) 36 | 37 | 38 | After each article is submitted it is added to the backlinks file. When all the submissions have been completed Open Submitter will submit the URLs to the indexing service. 39 | 40 | 41 | If any services are not working they can be disabled (ses below). 42 | 43 | 44 | ## Enabling and Disabling Unreliable Services 45 | 46 | Not all services are reliable and many seem to be down more than they are up. Unreliable services can be disabled and enabled back again when reliable. To disable a service open the services.txt file in the setting folder. We recommend using the free app [Notepad++][a35f49bf] as the formatting is not changed when editing: 47 | 48 | ![](./img/submit5.PNG) 49 | 50 | Now change the status of the service from ok to bad. 51 | 52 | ![](./img/submit4.PNG) 53 | 54 | **Note:** Make sure you do not change the file name, otherwise Open Submitter won't find it again. 55 | 56 | [a35f49bf]: https://notepad-plus-plus.org/ "Notepad++" 57 | 58 | 59 | [35fd80d0]: http://cmder.net/ "Cmder Console" 60 | -------------------------------------------------------------------------------- /docs/install-cli.md: -------------------------------------------------------------------------------- 1 | # Set Up Open Submitter 2 | 3 | How to set up the Open Submitter Command Line Interface (CLI). The CLI is required to submit articles to services. 4 | 5 | ## Prerequisites 6 | Please ensure the following prerequisite frameworks and applications are installed. 7 | 8 | - [NodeJS][ca1dffb7] v4.4.7 or greater 9 | - [PhantomJS][6997c770] v2.1 or greater 10 | - [CasperJS][476ee510] v1.1.1 or greater 11 | - [Cmder][9924c39d] (optional) 12 | - [The Best Spinner][a6914f8e] (optional) 13 | 14 | [ca1dffb7]: http://nodejs.org/ "NodeJS" 15 | [6997c770]: http://phantomjs.org/ "PhantomJS" 16 | [476ee510]: http://casperjs.org/ "CasperJS" 17 | [9924c39d]: http://cmder.net/ "Cmder" 18 | [a6914f8e]: http://paydotcom.net/r/95330/pcoady/27453918/ "The Best Spinner" 19 | 20 | 21 | ## Update Environment Variables 22 | Make sure your path environment variables are updated for NodeJS, PhantomJS, CasperJS and Cmder with the executable path. 23 | Depending on where you installed the software the paths will be similar to: 24 | - C:\Program Files\nodejs\ 25 | - C:\phantomjs 26 | - C:\casperjs\batchbin 27 | 28 | 29 | ## Check Prerequisities 30 | After the executables paths have been added to your environment variables you can check they are installed correctly using the following commands from the command line: 31 | - node --version 32 | - phantomjs --version 33 | - casperjs --version 34 | 35 | If everything is installed correctly each command will return the curent version details. 36 | 37 | If you have any problems installing the prerequisite frameworks please post a question on [Stack Overflow][0f0072cf]. 38 | 39 | 40 | [0f0072cf]: stackoverflow.com "Open Submitter Stack Overflow" 41 | 42 | ## Download latest release of Open Submitter 43 | 44 | Go to the main [repository page](https://github.com/BackSpaceTech/open-submitter). 45 | 46 | Click the releases. 47 | 48 | ![](./img/install4.PNG) 49 | 50 | Download archive file (zip or tar) 51 | 52 | ![](./img/install5.PNG) 53 | 54 | Extract archive to the location you want Open Submitter. 55 | 56 | ## Create additional required folders 57 | 58 | The following additional folders need to be created after the archive is extracted. Make sure all folder names are lowercase: 59 | - accounts 60 | - articles 61 | - backlinks 62 | - capture 63 | 64 | ![](./img/install6.PNG) 65 | 66 | ## Set up Sibbel 67 | 68 | Sibble will notify you by email of any repository changes to repositories you have starred. Always update immediately with new releases which can include bug fixes and new features and services. Sibbel does not spam you. 69 | 70 | First open a free GitHub account: 71 | 72 | ![](./img/install.PNG) 73 | 74 | Then star the Open Submitter repository: 75 | 76 | ![](./img/install2.PNG) 77 | 78 | Then go to to Sibbel.com and set up Sibble. 79 | 80 | ![](./img/install3.PNG) 81 | 82 | You will now be notified by email of any new releases to Open Submitter. 83 | ### When copying a new release over an old, make sure you save your accounts, backlinks and settings/indexers.txt files before copying the new files. 84 | 85 | [Documentation Home][bdc43f25] 86 | 87 | [bdc43f25]: readme.md "Open Submitter Documentation" 88 | -------------------------------------------------------------------------------- /docs/articles.md: -------------------------------------------------------------------------------- 1 | # Open Submitter Article Submissions 2 | 3 | Open Submitter article submission files contain the following information: 4 | - Title of article to be submitted in spin text. 5 | - Description of article in spin text. 6 | - Body of article in spin text. 7 | - Keywords in spin text and comma separated. 8 | - Link URLs in spin text and comma separated. 9 | - Image URLs in spin text and comma separated. 10 | 11 | ## Using Spin Syntax 12 | 13 | Spin syntax is used to allow Open Submitter to create unlimited unique articles to be submitted to services. Spin is surrounded by curly brackets {} and synonyms are separated by pipe symbols | e.g. 14 | 15 | **Phrase:** 16 | 17 | My great blog post. 18 | 19 | **Spin Syntax:** 20 | 21 | 22 | {My|A|This is a|A really} {great|awesome|cool} {blog post|article|review|commentary} 23 | 24 | **Example results after spinning** 25 | 26 | A cool commentary 27 | 28 | A really awesome commentary 29 | 30 | A great review 31 | 32 | This is a cool blog post 33 | 34 | My great commentary 35 | 36 | **Important Note** 37 | 38 | Do not nest spin as it will give unpredictable results with Open Submitter. e.g. 39 | 40 | Don't use this: 41 | 42 | {{this|this2}|this3} 43 | 44 | Only use this: 45 | 46 | {this|this2|this3} 47 | 48 | ## Spinning Tools 49 | 50 | Creating articles of any size in spin syntax manually is very slow process. The most popular tool used by professional SEO consultants to speed up this process is [The Best Spinner][3a94b86c]. 51 | 52 | ## Create an Article 53 | 54 | Open the GUI and click "Create Article" 55 | 56 | Enter the title, description and body of your article. Click Spin Preview to see the results after spinning. 57 | 58 | ![](./img/articles.PNG) 59 | 60 | ## Add Link Tags to Article 61 | 62 | To create backlinks in your article body and description where you want insert link tags (#links#). Open Submitter will insert a random keyword with a random link from the article keyword and link list. If no link tags are put in, Open Submitter will place one at the end. Do not insert too many link tags as search engines may reject the article as spam. Don't exceed one link per two paragraphs. The best results will come from having only one link only in the article body and description. Do not put links in title as these will not be recognised by Open Submitter. 63 | 64 | ![](./img/articles2.PNG) 65 | 66 | ## Add keywords, links. 67 | 68 | Keywords and links need to be supplied for Open Submitter to use. These are comma separated. Open Submitter will select randomly. Spin syntax can be used to group together long tail keywords and less important links. This way you can influence the ratio of selection of links and keywords. 69 | 70 | 71 | ![](./img/articles3.PNG) 72 | 73 | ## Add Images 74 | 75 | Images make articles look more interesting and less spammy. Open Submitter selects images at random from the images list supplied. These are comma separated URLs. The imgaes are randomly located vertically and randomly floating left or right. Please note not all services accept images. 76 | 77 | 78 | ![](./img/articles4.PNG) 79 | 80 | 81 | ## Create and Save Submission File 82 | 83 | Click on "Preview Submission" to see your final submission. 84 | 85 | ![](./img/articles5.PNG) 86 | 87 | ![](./img/articles6.PNG) 88 | 89 | 90 | Now Save the article submission file to the articles folder (you will need to create this folder). Please note it must be saved in the article folder only for open submitter to find it. Make sure the folder name is lowercase. If you have multiple submission files you can use multiple submission file names. All file names must have the .txt file extension. If you want multiple submissions in a single file simply use an editor such as Notepad++ and add them one after the other. Open Submitter will randomly select articles if multiple are available. 91 | 92 | 93 | 94 | ![](./img/articles7.PNG) 95 | 96 | 97 | [Documentation Home][91a747ec] 98 | 99 | [91a747ec]: readme.md "Open Submitter Documentation" 100 | 101 | 102 | [3a94b86c]: http://paydotcom.net/r/95330/pcoady/27453918/ "The Best Spinner" 103 | -------------------------------------------------------------------------------- /app/imports.coffee: -------------------------------------------------------------------------------- 1 | fs = require('fs') 2 | consolex = require('./console-xtra') 3 | 4 | exports.accounts = (filePath) -> 5 | # Load accounts.csv 6 | tempAccounts = [] 7 | if fs.exists(filePath) and fs.isFile(filePath) 8 | console.log 'Loading user accounts...' 9 | ins = fs.open(filePath, 'r') 10 | a = 0 11 | while !ins.atEnd() 12 | buffer = ins.readLine() 13 | temp = buffer.split(/\s*,\s*/) 14 | tempAccounts[a] = { 15 | accountType: temp[0] 16 | loginID: temp[1] 17 | password: temp[2] 18 | siteName: temp[3] 19 | } 20 | ++a 21 | tempAccounts # Return accounts 22 | else 23 | console.log 'Could not load ' + filePath 24 | 25 | exports.articles = (filePath) -> 26 | # Load Articles.txt 27 | tempArticles = [] 28 | articleStatus = '' 29 | firstLine = false 30 | if fs.exists(filePath) and fs.isFile(filePath) 31 | console.log 'Loading articles...' 32 | ins = fs.open(filePath, 'r') 33 | a = -1 34 | while !ins.atEnd() 35 | buffer = ins.readLine() 36 | temp = buffer.trim() 37 | if temp == '#Title' 38 | articleStatus = 'title' 39 | ++a 40 | tempArticles[a] = { 41 | title: '' 42 | description: '' 43 | body: '' 44 | keywords: '' 45 | links: '' 46 | images: '' 47 | } 48 | else if temp == '#Body' 49 | articleStatus = 'body' 50 | firstLine = true 51 | else if temp == '#Keywords' 52 | articleStatus = 'keywords' 53 | else if temp == '#Links' 54 | articleStatus = 'links' 55 | else if temp == '#Images' 56 | articleStatus = 'images' 57 | else if articleStatus == 'title' 58 | tempArticles[a].title += temp 59 | else if articleStatus == 'body' 60 | if firstLine and temp != '' 61 | tempArticles[a].description = temp + '
' 62 | firstLine = false 63 | tempArticles[a].body += temp + '
' 64 | else if articleStatus == 'keywords' 65 | temp = buffer.split(/\s*,\s*/) 66 | tempArticles[a].keywords = temp 67 | else if articleStatus == 'links' 68 | temp = buffer.split(/\s*,\s*/) 69 | tempArticles[a].links = temp 70 | else if articleStatus == 'images' 71 | temp = buffer.split(/\s*,\s*/) 72 | tempArticles[a].images = temp 73 | ins.close() 74 | a = 0 75 | tempArticles # Return Articles 76 | else 77 | console.log 'Could not load ' + filePath 78 | 79 | exports.indexers = (filePath) -> 80 | # Load Indexer.txt 81 | tempIndexers = [] 82 | status = '' 83 | if fs.exists(filePath) and fs.isFile(filePath) 84 | ins = fs.open(filePath, 'r') 85 | a = -1 86 | while !ins.atEnd() 87 | buffer = ins.readLine() 88 | temp = buffer.trim() 89 | if temp == '#name#' 90 | status = 'name' 91 | ++a 92 | tempIndexers[a] = { 93 | name: '' 94 | username: '' 95 | password: '' 96 | status: '' 97 | } 98 | else if temp == '#username#' 99 | status = 'username' 100 | else if temp == '#password#' 101 | status = 'password' 102 | else if temp == '#status#' 103 | status = 'status' 104 | else if status == 'name' 105 | tempIndexers[a].name = temp 106 | status = '' 107 | else if status == 'username' 108 | tempIndexers[a].username = temp 109 | status = '' 110 | else if status == 'password' 111 | tempIndexers[a].password = temp 112 | status = '' 113 | else if status == 'status' 114 | tempIndexers[a].status = temp 115 | status = '' 116 | ins.close() 117 | a = 0 118 | temp2 = 0 119 | tempIndexers2 = [] 120 | for i in [0...tempIndexers.length] 121 | if tempIndexers[i].status.toLowerCase() == 'ok' 122 | tempIndexers2[temp2] = tempIndexers[i] 123 | ++temp2 124 | tempIndexers2 # Return Indexer 125 | else 126 | console.log 'Could not load ' + filePath 127 | 128 | exports.services = (filePath) -> 129 | # Load Indexer.txt 130 | tempServices = [] 131 | status = '' 132 | if fs.exists(filePath) and fs.isFile(filePath) 133 | ins = fs.open(filePath, 'r') 134 | a = -1 135 | while !ins.atEnd() 136 | buffer = ins.readLine() 137 | temp = buffer.trim() 138 | if temp == '#name#' 139 | status = 'name' 140 | ++a 141 | tempServices[a] = { 142 | name: '' 143 | status: '' 144 | } 145 | else if temp == '#status#' 146 | status = 'status' 147 | else if status == 'name' 148 | tempServices[a].name = temp 149 | else if status == 'status' 150 | tempServices[a].status = temp 151 | ins.close() 152 | a = 0 153 | tempServices # Return Articles 154 | else 155 | console.log 'Could not load ' + filePath 156 | -------------------------------------------------------------------------------- /app/spinner.coffee: -------------------------------------------------------------------------------- 1 | fs = require('fs') 2 | consolex = require('./console-xtra') 3 | 4 | # -------------------- Get random account ---------------------------- 5 | 6 | exports.getAccount = (accounts, accountType) -> 7 | # Random wordpress account details 8 | tempRandomAccount = 9 | username: '' 10 | password: '' 11 | site: '' 12 | tempAccArray = accounts.filter (el) -> 13 | el.accountType == accountType 14 | if (tempAccArray.length > 0) 15 | randomAcc = Math.floor(Math.random() * tempAccArray.length) 16 | tempRandomAccount.username = tempAccArray[randomAcc].loginID 17 | tempRandomAccount.password = tempAccArray[randomAcc].password 18 | tempRandomAccount.site = tempAccArray[randomAcc].siteName 19 | else 20 | tempRandomAccount.username = 'no accounts' 21 | tempRandomAccount # Return a random account 22 | 23 | # -------------------- Create new spun article ---------------------------- 24 | 25 | spinner = (x) -> 26 | tempStr = '' 27 | tempSpinner = x.split( /\{([^}]+)\}/ ) 28 | y = 0 29 | while y < tempSpinner.length 30 | temp3 = tempSpinner[y].split( "|" ) 31 | tempStr += temp3[Math.floor(temp3.length*Math.random())] 32 | ++y 33 | tempStr 34 | 35 | spinnerLoop = (x) -> 36 | tempArray = [] 37 | y = 0 38 | while y < x.length 39 | tempArray[y] = spinner(x[y]) 40 | ++y 41 | tempArray 42 | 43 | exports.getArticle = (articles, microBlog, noHTML) -> 44 | # Create spun article 45 | a = Math.floor(articles.length*Math.random()) 46 | newArticle = 47 | title: '' 48 | body: '' 49 | keywords: [] 50 | links: [] 51 | images: [] 52 | 53 | # Spin article title 54 | console.log 'Spinning title for article # ' + a + '...' 55 | newArticle.title = spinner(articles[a].title) 56 | 57 | # Spin article keywords 58 | console.log 'Spinning keywords for article # ' + a + '...' 59 | newArticle.keywords = spinnerLoop(articles[a].keywords) 60 | 61 | # Spin article links 62 | console.log 'Spinning links for article # ' + a + '...' 63 | newArticle.links = spinnerLoop(articles[a].links) 64 | 65 | # Spin article images 66 | console.log 'Spinning images for article # ' + a + '...' 67 | newArticle.images = spinnerLoop(articles[a].images) 68 | 69 | # Spin article body / description 70 | console.log 'Spinning body of article # ' + a + '...' 71 | if microBlog 72 | temp = articles[a].description 73 | else 74 | temp = articles[a].body 75 | newArticle.body = spinner(temp) 76 | if noHTML 77 | newArticle.body = newArticle.body.replace('
', '\n') 78 | 79 | # Insert random links 80 | console.log 'Inserting random links in article # ' + a + '...' 81 | if !noHTML 82 | # Insert random links with random keywords in body 83 | tempIndex = 0 84 | while tempIndex < newArticle.keywords.length # Check for empty string 85 | if newArticle.keywords[tempIndex].trim().length == 0 86 | newArticle.keywords.splice(tempIndex, 1) 87 | ++tempIndex 88 | if newArticle.keywords.length == 0 # If no keywords 89 | newArticle.keywords[0] = 'here' 90 | if (newArticle.body.indexOf("#links#")) == -1 # No link tags 91 | newArticle.body += ' #links#' 92 | while (newArticle.body.indexOf("#links#")) != -1 93 | tempRandom = Math.floor(Math.random()*newArticle.links.length) 94 | randomLink = newArticle.links[tempRandom] 95 | tempRandom = Math.floor(Math.random()*newArticle.keywords.length) 96 | randomKeyword = newArticle.keywords[tempRandom] 97 | tempLink = ' ' + 98 | randomKeyword.toString().trim() + ' ' 99 | newArticle.body = newArticle.body.replace('#links#', tempLink) 100 | else 101 | # Remove link tags 102 | newArticle.body = newArticle.body.replace('#links#', ' ') 103 | # Insert random link at end of body 104 | temp = Math.floor(Math.random()*newArticle.links.length) 105 | randomLink = newArticle.links[temp] 106 | newArticle.body += (' ' + randomLink) 107 | 108 | # Add random image in a random position of body 109 | if !noHTML 110 | console.log 'Inserting random image in article # ' + a + '...' 111 | temp = newArticle.body.length 112 | floatPos = ['style="float:right"','style="float:left"'] 113 | randomFloat = Math.round(Math.random()) 114 | randomPos = Math.ceil(Math.random() * temp) 115 | randomImage = Math.floor(Math.random() * newArticle.images.length) 116 | # Split body and insert image. Make sure not splitting a word 117 | while newArticle.body.charAt(randomPos-1) != ' ' 118 | randomPos = Math.ceil(Math.random() * temp) 119 | temp1 = newArticle.body.slice(0, randomPos) 120 | temp2 = '' 122 | temp3 = newArticle.body.slice(randomPos, temp) 123 | newArticle.body = temp1 + temp2 + temp3 124 | 125 | consolex.log 'magenta', 'Created article: ' + newArticle.title 126 | newArticle # Return the article to submit 127 | -------------------------------------------------------------------------------- /app/spinner.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | var consolex, fs, spinner, spinnerLoop; 4 | 5 | fs = require('fs'); 6 | 7 | consolex = require('./console-xtra'); 8 | 9 | exports.getAccount = function(accounts, accountType) { 10 | var randomAcc, tempAccArray, tempRandomAccount; 11 | tempRandomAccount = { 12 | username: '', 13 | password: '', 14 | site: '' 15 | }; 16 | tempAccArray = accounts.filter(function(el) { 17 | return el.accountType === accountType; 18 | }); 19 | if (tempAccArray.length > 0) { 20 | randomAcc = Math.floor(Math.random() * tempAccArray.length); 21 | tempRandomAccount.username = tempAccArray[randomAcc].loginID; 22 | tempRandomAccount.password = tempAccArray[randomAcc].password; 23 | tempRandomAccount.site = tempAccArray[randomAcc].siteName; 24 | } else { 25 | tempRandomAccount.username = 'no accounts'; 26 | } 27 | return tempRandomAccount; 28 | }; 29 | 30 | spinner = function(x) { 31 | var temp3, tempSpinner, tempStr, y; 32 | tempStr = ''; 33 | tempSpinner = x.split(/\{([^}]+)\}/); 34 | y = 0; 35 | while (y < tempSpinner.length) { 36 | temp3 = tempSpinner[y].split("|"); 37 | tempStr += temp3[Math.floor(temp3.length * Math.random())]; 38 | ++y; 39 | } 40 | return tempStr; 41 | }; 42 | 43 | spinnerLoop = function(x) { 44 | var tempArray, y; 45 | tempArray = []; 46 | y = 0; 47 | while (y < x.length) { 48 | tempArray[y] = spinner(x[y]); 49 | ++y; 50 | } 51 | return tempArray; 52 | }; 53 | 54 | exports.getArticle = function(articles, microBlog, noHTML) { 55 | var a, floatPos, newArticle, randomFloat, randomImage, randomKeyword, randomLink, randomPos, temp, temp1, temp2, temp3, tempIndex, tempLink, tempRandom; 56 | a = Math.floor(articles.length * Math.random()); 57 | newArticle = { 58 | title: '', 59 | body: '', 60 | keywords: [], 61 | links: [], 62 | images: [] 63 | }; 64 | console.log('Spinning title for article # ' + a + '...'); 65 | newArticle.title = spinner(articles[a].title); 66 | console.log('Spinning keywords for article # ' + a + '...'); 67 | newArticle.keywords = spinnerLoop(articles[a].keywords); 68 | console.log('Spinning links for article # ' + a + '...'); 69 | newArticle.links = spinnerLoop(articles[a].links); 70 | console.log('Spinning images for article # ' + a + '...'); 71 | newArticle.images = spinnerLoop(articles[a].images); 72 | console.log('Spinning body of article # ' + a + '...'); 73 | if (microBlog) { 74 | temp = articles[a].description; 75 | } else { 76 | temp = articles[a].body; 77 | } 78 | newArticle.body = spinner(temp); 79 | if (noHTML) { 80 | newArticle.body = newArticle.body.replace('
', '\n'); 81 | } 82 | console.log('Inserting random links in article # ' + a + '...'); 83 | if (!noHTML) { 84 | tempIndex = 0; 85 | while (tempIndex < newArticle.keywords.length) { 86 | if (newArticle.keywords[tempIndex].trim().length === 0) { 87 | newArticle.keywords.splice(tempIndex, 1); 88 | } 89 | ++tempIndex; 90 | } 91 | if (newArticle.keywords.length === 0) { 92 | newArticle.keywords[0] = 'here'; 93 | } 94 | if ((newArticle.body.indexOf("#links#")) === -1) { 95 | newArticle.body += ' #links#'; 96 | } 97 | while ((newArticle.body.indexOf("#links#")) !== -1) { 98 | tempRandom = Math.floor(Math.random() * newArticle.links.length); 99 | randomLink = newArticle.links[tempRandom]; 100 | tempRandom = Math.floor(Math.random() * newArticle.keywords.length); 101 | randomKeyword = newArticle.keywords[tempRandom]; 102 | tempLink = ' ' + randomKeyword.toString().trim() + ' '; 103 | newArticle.body = newArticle.body.replace('#links#', tempLink); 104 | } 105 | } else { 106 | newArticle.body = newArticle.body.replace('#links#', ' '); 107 | temp = Math.floor(Math.random() * newArticle.links.length); 108 | randomLink = newArticle.links[temp]; 109 | newArticle.body += ' ' + randomLink; 110 | } 111 | if (!noHTML) { 112 | console.log('Inserting random image in article # ' + a + '...'); 113 | temp = newArticle.body.length; 114 | floatPos = ['style="float:right"', 'style="float:left"']; 115 | randomFloat = Math.round(Math.random()); 116 | randomPos = Math.ceil(Math.random() * temp); 117 | randomImage = Math.floor(Math.random() * newArticle.images.length); 118 | while (newArticle.body.charAt(randomPos - 1) !== ' ') { 119 | randomPos = Math.ceil(Math.random() * temp); 120 | } 121 | temp1 = newArticle.body.slice(0, randomPos); 122 | temp2 = ''; 123 | temp3 = newArticle.body.slice(randomPos, temp); 124 | newArticle.body = temp1 + temp2 + temp3; 125 | } 126 | consolex.log('magenta', 'Created article: ' + newArticle.title); 127 | return newArticle; 128 | }; 129 | 130 | }).call(this); 131 | -------------------------------------------------------------------------------- /app/imports.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | var consolex, fs; 4 | 5 | fs = require('fs'); 6 | 7 | consolex = require('./console-xtra'); 8 | 9 | exports.accounts = function(filePath) { 10 | var a, buffer, ins, temp, tempAccounts; 11 | tempAccounts = []; 12 | if (fs.exists(filePath) && fs.isFile(filePath)) { 13 | console.log('Loading user accounts...'); 14 | ins = fs.open(filePath, 'r'); 15 | a = 0; 16 | while (!ins.atEnd()) { 17 | buffer = ins.readLine(); 18 | temp = buffer.split(/\s*,\s*/); 19 | tempAccounts[a] = { 20 | accountType: temp[0], 21 | loginID: temp[1], 22 | password: temp[2], 23 | siteName: temp[3] 24 | }; 25 | ++a; 26 | } 27 | return tempAccounts; 28 | } else { 29 | return console.log('Could not load ' + filePath); 30 | } 31 | }; 32 | 33 | exports.articles = function(filePath) { 34 | var a, articleStatus, buffer, firstLine, ins, temp, tempArticles; 35 | tempArticles = []; 36 | articleStatus = ''; 37 | firstLine = false; 38 | if (fs.exists(filePath) && fs.isFile(filePath)) { 39 | console.log('Loading articles...'); 40 | ins = fs.open(filePath, 'r'); 41 | a = -1; 42 | while (!ins.atEnd()) { 43 | buffer = ins.readLine(); 44 | temp = buffer.trim(); 45 | if (temp === '#Title') { 46 | articleStatus = 'title'; 47 | ++a; 48 | tempArticles[a] = { 49 | title: '', 50 | description: '', 51 | body: '', 52 | keywords: '', 53 | links: '', 54 | images: '' 55 | }; 56 | } else if (temp === '#Body') { 57 | articleStatus = 'body'; 58 | firstLine = true; 59 | } else if (temp === '#Keywords') { 60 | articleStatus = 'keywords'; 61 | } else if (temp === '#Links') { 62 | articleStatus = 'links'; 63 | } else if (temp === '#Images') { 64 | articleStatus = 'images'; 65 | } else if (articleStatus === 'title') { 66 | tempArticles[a].title += temp; 67 | } else if (articleStatus === 'body') { 68 | if (firstLine && temp !== '') { 69 | tempArticles[a].description = temp + '
'; 70 | firstLine = false; 71 | } 72 | tempArticles[a].body += temp + '
'; 73 | } else if (articleStatus === 'keywords') { 74 | temp = buffer.split(/\s*,\s*/); 75 | tempArticles[a].keywords = temp; 76 | } else if (articleStatus === 'links') { 77 | temp = buffer.split(/\s*,\s*/); 78 | tempArticles[a].links = temp; 79 | } else if (articleStatus === 'images') { 80 | temp = buffer.split(/\s*,\s*/); 81 | tempArticles[a].images = temp; 82 | } 83 | } 84 | ins.close(); 85 | a = 0; 86 | return tempArticles; 87 | } else { 88 | return console.log('Could not load ' + filePath); 89 | } 90 | }; 91 | 92 | exports.indexers = function(filePath) { 93 | var a, buffer, i, ins, status, temp, temp2, tempIndexers, tempIndexers2, _i, _ref; 94 | tempIndexers = []; 95 | status = ''; 96 | if (fs.exists(filePath) && fs.isFile(filePath)) { 97 | ins = fs.open(filePath, 'r'); 98 | a = -1; 99 | while (!ins.atEnd()) { 100 | buffer = ins.readLine(); 101 | temp = buffer.trim(); 102 | if (temp === '#name#') { 103 | status = 'name'; 104 | ++a; 105 | tempIndexers[a] = { 106 | name: '', 107 | username: '', 108 | password: '', 109 | status: '' 110 | }; 111 | } else if (temp === '#username#') { 112 | status = 'username'; 113 | } else if (temp === '#password#') { 114 | status = 'password'; 115 | } else if (temp === '#status#') { 116 | status = 'status'; 117 | } else if (status === 'name') { 118 | tempIndexers[a].name = temp; 119 | status = ''; 120 | } else if (status === 'username') { 121 | tempIndexers[a].username = temp; 122 | status = ''; 123 | } else if (status === 'password') { 124 | tempIndexers[a].password = temp; 125 | status = ''; 126 | } else if (status === 'status') { 127 | tempIndexers[a].status = temp; 128 | status = ''; 129 | } 130 | } 131 | ins.close(); 132 | a = 0; 133 | temp2 = 0; 134 | tempIndexers2 = []; 135 | for (i = _i = 0, _ref = tempIndexers.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { 136 | if (tempIndexers[i].status.toLowerCase() === 'ok') { 137 | tempIndexers2[temp2] = tempIndexers[i]; 138 | ++temp2; 139 | } 140 | } 141 | return tempIndexers2; 142 | } else { 143 | return console.log('Could not load ' + filePath); 144 | } 145 | }; 146 | 147 | exports.services = function(filePath) { 148 | var a, buffer, ins, status, temp, tempServices; 149 | tempServices = []; 150 | status = ''; 151 | if (fs.exists(filePath) && fs.isFile(filePath)) { 152 | ins = fs.open(filePath, 'r'); 153 | a = -1; 154 | while (!ins.atEnd()) { 155 | buffer = ins.readLine(); 156 | temp = buffer.trim(); 157 | if (temp === '#name#') { 158 | status = 'name'; 159 | ++a; 160 | tempServices[a] = { 161 | name: '', 162 | status: '' 163 | }; 164 | } else if (temp === '#status#') { 165 | status = 'status'; 166 | } else if (status === 'name') { 167 | tempServices[a].name = temp; 168 | } else if (status === 'status') { 169 | tempServices[a].status = temp; 170 | } 171 | } 172 | ins.close(); 173 | a = 0; 174 | return tempServices; 175 | } else { 176 | return console.log('Could not load ' + filePath); 177 | } 178 | }; 179 | 180 | }).call(this); 181 | -------------------------------------------------------------------------------- /open-submitter.coffee: -------------------------------------------------------------------------------- 1 | fs = require('fs') 2 | system = require('system') 3 | consolex = require('./app/console-xtra') 4 | imports = require('./app/imports') 5 | spinner = require('./app/spinner') 6 | page = require('webpage').create() 7 | 8 | casper = require('casper').create( 9 | pageSettings: webSecurityEnabled: false 10 | viewportSize: {width: 800, height: 600} 11 | timeout: 3600000 # 1 hour general timeout 12 | stepTimeout: 300000 # 5 min default step timeout 13 | waitTimeout: 60000 # 1 min default wait timeout 14 | verbose: true 15 | onError: (self, msg) -> 16 | consolex.log 'red', 'FATAL:' + msg 17 | self.exit() 18 | return 19 | onTimeout: (self, msg) -> 20 | @.capture('./capture/timeout.png') 21 | consolex.log 'red', 'general timeout error: ' + msg 22 | return 23 | onStepTimeout: (self, msg) -> 24 | @.capture('./capture/timeout.png') 25 | consolex.log 'red', 'step timeout error: step ' + msg 26 | return 27 | onWaitTimeout: (self, msg) -> 28 | @.capture ('./capture/timeout.png') 29 | consolex.log 'red','wait timeout error: ' + msg 30 | return 31 | ) 32 | 33 | casper.userAgent 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 ' + 34 | '(KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' 35 | 36 | fileAccounts = './accounts/' + casper.cli.get(0) + '.csv' 37 | fileArticles = './articles/' + casper.cli.get(1) + '.txt' 38 | fileBacklinks = './backlinks/' + casper.cli.get(2) + '.txt' 39 | numPosts = casper.cli.get(3) 40 | 41 | console.log '\n' 42 | consolex.log 'cyan', '---------------- Submission Details --------------------' 43 | consolex.log 'cyan', 'Accounts file: ' + fileAccounts 44 | consolex.log 'cyan', 'Articles file: ' + fileArticles 45 | consolex.log 'cyan', 'Backlinks saved to file: ' + fileBacklinks 46 | consolex.log 'cyan', 'Number of Submissions: ' + numPosts 47 | 48 | currentService = 0 49 | currentStep = 0 50 | submitArticle = 51 | title: '' 52 | body: '' 53 | keywords: '' 54 | 55 | # Import settings 56 | services = imports.services('./settings/services.txt') 57 | indexerDetails = imports.indexers('./settings/indexers.txt') 58 | 59 | # Load services 60 | numLoops = 0 61 | service = [] 62 | currentService = 0 63 | for i in [0...services.length] 64 | if services[i].status.toLowerCase() == 'ok' 65 | service[currentService] = require('./services/' + services[i].name) 66 | numLoops += service[currentService].steps.length 67 | ++currentService 68 | numLoops *= numPosts 69 | 70 | # Load indexer 71 | numIndexerLoops = 0 72 | indexers = [] 73 | indexersLogin = [] 74 | currentIndexer = 0 75 | for i in [0...indexerDetails.length] 76 | if indexerDetails[i].status.toLowerCase() == 'ok' 77 | indexers[currentIndexer] = require('./indexers/' + indexerDetails[i].name) 78 | indexersLogin[currentIndexer] = indexerDetails[i] 79 | numIndexerLoops += indexers[currentIndexer].steps.length 80 | ++currentIndexer 81 | 82 | # ---------------- Import Files ------------------------ 83 | 84 | console.log ('------------------- Import Files -------------------------') 85 | accounts = imports.accounts(fileAccounts) 86 | articles = imports.articles(fileArticles) 87 | 88 | # ------------------ Utils ------------------------ 89 | 90 | currentStep = 0 91 | randomAccount = 92 | username: '' 93 | password: '' 94 | site: '' 95 | submitArticle = 96 | title: '' 97 | body: '' 98 | keywords: '' 99 | backlinksList = '' 100 | 101 | skipService = -> 102 | console.log 'Skipping ' + service[currentService].name 103 | ++currentService 104 | currentStep = 0 105 | 106 | errorMsg = -> 107 | console.log 'Failed step ' + currentStep 108 | console.log 'Check error.png file' 109 | skipService() 110 | 111 | # ------------------------ Step Commands ------------------------------ 112 | 113 | currentSubmission = 0 114 | currentService = 0 115 | currentIndexer = 0 116 | currentIndexerStep = 0 117 | 118 | casper.doStep = (objStep, serviceName) -> 119 | @echo 'Step: ' + currentStep 120 | # -------------------------- Create ------------------------------------- 121 | if objStep.command == 'create' 122 | @echo 'Creating article...' 123 | submitArticle = spinner.getArticle(articles, objStep.micro,objStep.noHTML) 124 | randomAccount = spinner.getAccount(accounts, serviceName) 125 | str = '-------------- Submit to ' + serviceName+' ----------------' 126 | consolex.log 'yellow', str 127 | # -------------------------- Open --------------------------------------- 128 | else if objStep.command == 'open' 129 | @echo 'Opening url '+objStep.url+'...' 130 | @open(objStep.url).then -> 131 | @capture('./capture/capture' + currentStep + '.png') 132 | if objStep.confirm 133 | @waitForSelector objStep.confirm, 134 | -> 135 | @echo 'Opened url' 136 | -> 137 | errorMsg() 138 | @capture('./capture/error.png') 139 | else if objStep.confirmtxt 140 | @waitForText objStep.confirmtxt, 141 | -> 142 | @echo 'Opened url' 143 | -> 144 | errorMsg() 145 | @capture('./capture/error.png') 146 | # -------------------------- Open Site ----------------------------------- 147 | else if objStep.command == 'open-site' 148 | tempURL = objStep.begin + randomAccount.site + objStep.end 149 | @echo 'Opening url ' + tempURL + '...' 150 | @open(tempURL).then -> 151 | @capture('./capture/capture' + currentStep + '.png') 152 | if objStep.confirm 153 | @waitForSelector objStep.confirm, 154 | -> 155 | @echo 'Opened url' 156 | -> 157 | errorMsg() 158 | @capture('./capture/error.png') 159 | else if objStep.confirmtxt 160 | @waitForText objStep.confirmtxt, 161 | -> 162 | @echo 'Opened url' 163 | -> 164 | errorMsg() 165 | @capture('./capture/error.png') 166 | # -------------------------- Login ---------------------------------------- 167 | else if objStep.command == 'login' 168 | if randomAccount.username == 'no accounts' 169 | @echo 'No '+ serviceName + ' accounts!' 170 | skipService() 171 | else 172 | @echo 'Logging in: ' + randomAccount.username + '...' 173 | # Login to WordPress with random account 174 | tempObj = 175 | formElem: objStep.form 176 | nameElem: objStep.username 177 | pwdElem: objStep.password 178 | name: randomAccount.username 179 | pwd: randomAccount.password 180 | submit: objStep.submit 181 | @evaluate ((s) -> 182 | document.querySelector(s.nameElem).value = s.name 183 | document.querySelector(s.pwdElem).value = s.pwd 184 | if s.submit 185 | document.querySelector(s.formElem).submit() 186 | return 187 | ), tempObj 188 | @capture('./capture/capture' + currentStep + '.png') 189 | @echo 'Waiting for login confirmation...' 190 | if objStep.submit 191 | @waitForSelector objStep.confirm, 192 | -> 193 | @echo 'Login success.' 194 | -> 195 | errorMsg() 196 | @capture('./capture/error.png') 197 | else if objStep.confirmtxt 198 | @waitForText objStep.confirmtxt, 199 | -> 200 | @echo 'Login success.' 201 | -> 202 | errorMsg() 203 | @capture('./capture/error.png') 204 | # -------------------------- Login-Indexer ----------------------------------- 205 | else if objStep.command == 'login-indexer' 206 | @capture('./capture/indexer0.png') 207 | if indexersLogin.length == 0 208 | @echo 'No indexer accounts set up!' 209 | else 210 | @echo 'Logging in: ' + 211 | indexersLogin[currentIndexer].username + '...' 212 | # Login to Indexer 213 | tempObj = 214 | formElem: objStep.form 215 | nameElem: objStep.username 216 | pwdElem: objStep.password 217 | name: indexersLogin[currentIndexer].username 218 | pwd: indexersLogin[currentIndexer].password 219 | submit: objStep.submit 220 | @evaluate ((s) -> 221 | document.querySelector(s.nameElem).value = s.name 222 | document.querySelector(s.pwdElem).value = s.pwd 223 | if s.submit 224 | document.querySelector(s.formElem).submit() 225 | return 226 | ), tempObj 227 | @capture('./capture/indexer1.png') 228 | @echo 'Waiting for login confirmation...' 229 | if objStep.confirm 230 | @waitForSelector objStep.confirm, 231 | -> 232 | @echo 'Login success.' 233 | -> 234 | @capture('./capture/error.png') 235 | errorMsg() 236 | else if objStep.confirmtxt 237 | @waitForText objStep.confirmtxt, 238 | -> 239 | @echo 'Login success.' 240 | -> 241 | @capture('./capture/error.png') 242 | errorMsg() 243 | # --------------------------- Click --------------------------------------- 244 | if objStep.command == 'click' 245 | if objStep.selector 246 | tempObj = objStep.selector 247 | else if objStep.xpath 248 | tempObj = { 249 | type: 'xpath', 250 | path: objStep.xpath 251 | } 252 | if @exists(tempObj) 253 | @click tempObj 254 | @echo 'Clicked on DOM selector' 255 | if objStep.confirm 256 | @waitForSelector objStep.confirm, 257 | -> 258 | @echo 'Found confirm selector.' 259 | -> 260 | @echo 'Confirm DOM selector not found', 'ERROR' 261 | errorMsg() 262 | @capture('./capture/error.png') 263 | if objStep.confirmtxt 264 | @waitForText objStep.confirmtxt, 265 | -> 266 | @echo 'Found confirm text: ' + objStep.confirmtxt 267 | -> 268 | @echo 'Confirm text' + objStep.confirmtxt + 'not found', 'ERROR' 269 | errorMsg() 270 | @capture('./capture/error.png') 271 | else 272 | @echo 'DOM selector not found', 'ERROR' 273 | errorMsg() 274 | # --------------------------- Wait --------------------------------------- 275 | if objStep.command == 'wait' 276 | @echo 'Waiting for ' + objStep.value + ' ms' 277 | @wait objStep.value, -> 278 | @echo 'Finished wait time.' 279 | return 280 | # --------------------------- Title --------------------------------------- 281 | if objStep.command == 'title' 282 | if objStep.selector 283 | tempObj = objStep.selector 284 | else if objStep.xpath 285 | tempObj = { 286 | type: 'xpath', 287 | path: objStep.xpath 288 | } 289 | if @exists(tempObj) 290 | @sendKeys(tempObj, submitArticle.title) 291 | @echo 'Entered title' 292 | else 293 | @echo 'Input field not found', 'ERROR' 294 | errorMsg() 295 | # --------------------------- Title --------------------------------------- 296 | if objStep.command == 'backlinks' 297 | if objStep.selector 298 | tempObj = objStep.selector 299 | else if objStep.xpath 300 | tempObj = { 301 | type: 'xpath', 302 | path: objStep.xpath 303 | } 304 | if @exists(tempObj) 305 | @sendKeys(tempObj, backlinksList) 306 | @echo 'Entered backlinks list' 307 | else 308 | @echo 'Input field not found', 'ERROR' 309 | errorMsg() 310 | # --------------------------- Body --------------------------------------- 311 | if objStep.command == 'body' 312 | if objStep.selector 313 | tempObj = objStep.selector 314 | else if objStep.xpath 315 | tempObj = { 316 | type: 'xpath', 317 | path: objStep.xpath 318 | } 319 | if @exists(tempObj) 320 | @sendKeys(tempObj, submitArticle.body) 321 | @echo 'Entered body' 322 | else 323 | @echo 'Input field not found', 'ERROR' 324 | errorMsg() 325 | # --------------------------- Save-href ----------------------------------- 326 | if objStep.command == 'save-href' 327 | if objStep.selector 328 | tempObj = objStep.selector 329 | else if objStep.xpath 330 | tempObj = { 331 | type: 'xpath', 332 | path: objStep.xpath 333 | } 334 | if @exists(tempObj) 335 | submitURL = @getElementAttribute tempObj, 'href' 336 | backlinksList += submitURL + '\n' 337 | consolex.log 'cyan', 'Submitted post to URL: ' + submitURL 338 | # Save backlinks.txt 339 | try 340 | fs.write fileBacklinks, submitURL, 'a' 341 | fs.write fileBacklinks, '\n', 'a' 342 | catch e 343 | @echo e 344 | @echo 'Saved backlink to ' + fileBacklinks 345 | else 346 | @echo 'DOM selector not found' +tempObj, 'ERROR' 347 | errorMsg() 348 | 349 | # ------------------ Submit to Services ------------------------ 350 | 351 | casper.start() 352 | casper.repeat numLoops, -> 353 | @then -> 354 | if currentService >= service.length 355 | ++currentSubmission 356 | currentService = 0 357 | currentStep = 0 358 | if currentSubmission < numPosts 359 | serviceName = service[currentService].name 360 | objStep = service[currentService].steps[currentStep] 361 | @.doStep(objStep, serviceName) 362 | @then -> 363 | @capture('./capture/capture' + currentStep + '.png') 364 | ++currentStep 365 | if currentStep == service[currentService].steps.length 366 | serviceName = service[currentService].name 367 | consolex.log 'green', 'Completed submit to '+serviceName + '\n' 368 | ++currentService 369 | currentStep = 0 370 | return 371 | return 372 | 373 | casper.then -> 374 | consolex.log 'blue', 'Submitting links to indexeing services' 375 | 376 | casper.repeat numIndexerLoops, -> 377 | @then -> 378 | if currentIndexer < indexers.length 379 | serviceName = indexers[currentIndexer].name 380 | objStep = indexers[currentIndexer].steps[currentIndexerStep] 381 | @.doStep(objStep, serviceName) 382 | ++currentIndexerStep 383 | if currentIndexerStep == indexers[currentIndexer].steps.length 384 | ++currentIndexer 385 | currentIndexerStep = 0 386 | 387 | casper.run -> 388 | consolex.log 'green', 'Finished all submissions.' 389 | @echo 'Press ctrl C to exit' 390 | @exit(0) 391 | @bypass(1) 392 | return 393 | # 394 | -------------------------------------------------------------------------------- /open-submitter.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.3.3 2 | (function() { 3 | var accounts, articles, backlinksList, casper, consolex, currentIndexer, currentIndexerStep, currentService, currentStep, currentSubmission, errorMsg, fileAccounts, fileArticles, fileBacklinks, fs, i, imports, indexerDetails, indexers, indexersLogin, numIndexerLoops, numLoops, numPosts, page, randomAccount, service, services, skipService, spinner, submitArticle, system, _i, _j, _ref, _ref1; 4 | 5 | fs = require('fs'); 6 | 7 | system = require('system'); 8 | 9 | consolex = require('./app/console-xtra'); 10 | 11 | imports = require('./app/imports'); 12 | 13 | spinner = require('./app/spinner'); 14 | 15 | page = require('webpage').create(); 16 | 17 | casper = require('casper').create({ 18 | pageSettings: { 19 | webSecurityEnabled: false 20 | }, 21 | viewportSize: { 22 | width: 800, 23 | height: 600 24 | }, 25 | timeout: 3600000, 26 | stepTimeout: 300000, 27 | waitTimeout: 60000, 28 | verbose: true, 29 | onError: function(self, msg) { 30 | consolex.log('red', 'FATAL:' + msg); 31 | self.exit(); 32 | }, 33 | onTimeout: function(self, msg) { 34 | this.capture('./capture/timeout.png'); 35 | consolex.log('red', 'general timeout error: ' + msg); 36 | }, 37 | onStepTimeout: function(self, msg) { 38 | this.capture('./capture/timeout.png'); 39 | consolex.log('red', 'step timeout error: step ' + msg); 40 | }, 41 | onWaitTimeout: function(self, msg) { 42 | this.capture('./capture/timeout.png'); 43 | consolex.log('red', 'wait timeout error: ' + msg); 44 | } 45 | }); 46 | 47 | casper.userAgent('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 ' + '(KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'); 48 | 49 | fileAccounts = './accounts/' + casper.cli.get(0) + '.csv'; 50 | 51 | fileArticles = './articles/' + casper.cli.get(1) + '.txt'; 52 | 53 | fileBacklinks = './backlinks/' + casper.cli.get(2) + '.txt'; 54 | 55 | numPosts = casper.cli.get(3); 56 | 57 | console.log('\n'); 58 | 59 | consolex.log('cyan', '---------------- Submission Details --------------------'); 60 | 61 | consolex.log('cyan', 'Accounts file: ' + fileAccounts); 62 | 63 | consolex.log('cyan', 'Articles file: ' + fileArticles); 64 | 65 | consolex.log('cyan', 'Backlinks saved to file: ' + fileBacklinks); 66 | 67 | consolex.log('cyan', 'Number of Submissions: ' + numPosts); 68 | 69 | currentService = 0; 70 | 71 | currentStep = 0; 72 | 73 | submitArticle = { 74 | title: '', 75 | body: '', 76 | keywords: '' 77 | }; 78 | 79 | services = imports.services('./settings/services.txt'); 80 | 81 | indexerDetails = imports.indexers('./settings/indexers.txt'); 82 | 83 | numLoops = 0; 84 | 85 | service = []; 86 | 87 | currentService = 0; 88 | 89 | for (i = _i = 0, _ref = services.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { 90 | if (services[i].status.toLowerCase() === 'ok') { 91 | service[currentService] = require('./services/' + services[i].name); 92 | numLoops += service[currentService].steps.length; 93 | ++currentService; 94 | } 95 | } 96 | 97 | numLoops *= numPosts; 98 | 99 | numIndexerLoops = 0; 100 | 101 | indexers = []; 102 | 103 | indexersLogin = []; 104 | 105 | currentIndexer = 0; 106 | 107 | for (i = _j = 0, _ref1 = indexerDetails.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) { 108 | if (indexerDetails[i].status.toLowerCase() === 'ok') { 109 | indexers[currentIndexer] = require('./indexers/' + indexerDetails[i].name); 110 | indexersLogin[currentIndexer] = indexerDetails[i]; 111 | numIndexerLoops += indexers[currentIndexer].steps.length; 112 | ++currentIndexer; 113 | } 114 | } 115 | 116 | console.log('------------------- Import Files -------------------------'); 117 | 118 | accounts = imports.accounts(fileAccounts); 119 | 120 | articles = imports.articles(fileArticles); 121 | 122 | currentStep = 0; 123 | 124 | randomAccount = { 125 | username: '', 126 | password: '', 127 | site: '' 128 | }; 129 | 130 | submitArticle = { 131 | title: '', 132 | body: '', 133 | keywords: '' 134 | }; 135 | 136 | backlinksList = ''; 137 | 138 | skipService = function() { 139 | console.log('Skipping ' + service[currentService].name); 140 | ++currentService; 141 | return currentStep = 0; 142 | }; 143 | 144 | errorMsg = function() { 145 | console.log('Failed step ' + currentStep); 146 | console.log('Check error.png file'); 147 | return skipService(); 148 | }; 149 | 150 | currentSubmission = 0; 151 | 152 | currentService = 0; 153 | 154 | currentIndexer = 0; 155 | 156 | currentIndexerStep = 0; 157 | 158 | casper.doStep = function(objStep, serviceName) { 159 | var str, submitURL, tempObj, tempURL; 160 | this.echo('Step: ' + currentStep); 161 | if (objStep.command === 'create') { 162 | this.echo('Creating article...'); 163 | submitArticle = spinner.getArticle(articles, objStep.micro, objStep.noHTML); 164 | randomAccount = spinner.getAccount(accounts, serviceName); 165 | str = '-------------- Submit to ' + serviceName + ' ----------------'; 166 | consolex.log('yellow', str); 167 | } else if (objStep.command === 'open') { 168 | this.echo('Opening url ' + objStep.url + '...'); 169 | this.open(objStep.url).then(function() { 170 | this.capture('./capture/capture' + currentStep + '.png'); 171 | if (objStep.confirm) { 172 | return this.waitForSelector(objStep.confirm, function() { 173 | return this.echo('Opened url'); 174 | }, function() { 175 | errorMsg(); 176 | return this.capture('./capture/error.png'); 177 | }); 178 | } else if (objStep.confirmtxt) { 179 | return this.waitForText(objStep.confirmtxt, function() { 180 | return this.echo('Opened url'); 181 | }, function() { 182 | errorMsg(); 183 | return this.capture('./capture/error.png'); 184 | }); 185 | } 186 | }); 187 | } else if (objStep.command === 'open-site') { 188 | tempURL = objStep.begin + randomAccount.site + objStep.end; 189 | this.echo('Opening url ' + tempURL + '...'); 190 | this.open(tempURL).then(function() { 191 | this.capture('./capture/capture' + currentStep + '.png'); 192 | if (objStep.confirm) { 193 | return this.waitForSelector(objStep.confirm, function() { 194 | return this.echo('Opened url'); 195 | }, function() { 196 | errorMsg(); 197 | return this.capture('./capture/error.png'); 198 | }); 199 | } else if (objStep.confirmtxt) { 200 | return this.waitForText(objStep.confirmtxt, function() { 201 | return this.echo('Opened url'); 202 | }, function() { 203 | errorMsg(); 204 | return this.capture('./capture/error.png'); 205 | }); 206 | } 207 | }); 208 | } else if (objStep.command === 'login') { 209 | if (randomAccount.username === 'no accounts') { 210 | this.echo('No ' + serviceName + ' accounts!'); 211 | skipService(); 212 | } else { 213 | this.echo('Logging in: ' + randomAccount.username + '...'); 214 | tempObj = { 215 | formElem: objStep.form, 216 | nameElem: objStep.username, 217 | pwdElem: objStep.password, 218 | name: randomAccount.username, 219 | pwd: randomAccount.password, 220 | submit: objStep.submit 221 | }; 222 | this.evaluate((function(s) { 223 | document.querySelector(s.nameElem).value = s.name; 224 | document.querySelector(s.pwdElem).value = s.pwd; 225 | if (s.submit) { 226 | document.querySelector(s.formElem).submit(); 227 | } 228 | }), tempObj); 229 | this.capture('./capture/capture' + currentStep + '.png'); 230 | this.echo('Waiting for login confirmation...'); 231 | if (objStep.submit) { 232 | this.waitForSelector(objStep.confirm, function() { 233 | return this.echo('Login success.'); 234 | }, function() { 235 | errorMsg(); 236 | return this.capture('./capture/error.png'); 237 | }); 238 | } else if (objStep.confirmtxt) { 239 | this.waitForText(objStep.confirmtxt, function() { 240 | return this.echo('Login success.'); 241 | }, function() { 242 | errorMsg(); 243 | return this.capture('./capture/error.png'); 244 | }); 245 | } 246 | } 247 | } else if (objStep.command === 'login-indexer') { 248 | this.capture('./capture/indexer0.png'); 249 | if (indexersLogin.length === 0) { 250 | this.echo('No indexer accounts set up!'); 251 | } else { 252 | this.echo('Logging in: ' + indexersLogin[currentIndexer].username + '...'); 253 | tempObj = { 254 | formElem: objStep.form, 255 | nameElem: objStep.username, 256 | pwdElem: objStep.password, 257 | name: indexersLogin[currentIndexer].username, 258 | pwd: indexersLogin[currentIndexer].password, 259 | submit: objStep.submit 260 | }; 261 | this.evaluate((function(s) { 262 | document.querySelector(s.nameElem).value = s.name; 263 | document.querySelector(s.pwdElem).value = s.pwd; 264 | if (s.submit) { 265 | document.querySelector(s.formElem).submit(); 266 | } 267 | }), tempObj); 268 | this.capture('./capture/indexer1.png'); 269 | this.echo('Waiting for login confirmation...'); 270 | if (objStep.confirm) { 271 | this.waitForSelector(objStep.confirm, function() { 272 | return this.echo('Login success.'); 273 | }, function() { 274 | this.capture('./capture/error.png'); 275 | return errorMsg(); 276 | }); 277 | } else if (objStep.confirmtxt) { 278 | this.waitForText(objStep.confirmtxt, function() { 279 | return this.echo('Login success.'); 280 | }, function() { 281 | this.capture('./capture/error.png'); 282 | return errorMsg(); 283 | }); 284 | } 285 | } 286 | } 287 | if (objStep.command === 'click') { 288 | if (objStep.selector) { 289 | tempObj = objStep.selector; 290 | } else if (objStep.xpath) { 291 | tempObj = { 292 | type: 'xpath', 293 | path: objStep.xpath 294 | }; 295 | } 296 | if (this.exists(tempObj)) { 297 | this.click(tempObj); 298 | this.echo('Clicked on DOM selector'); 299 | if (objStep.confirm) { 300 | this.waitForSelector(objStep.confirm, function() { 301 | return this.echo('Found confirm selector.'); 302 | }, function() { 303 | this.echo('Confirm DOM selector not found', 'ERROR'); 304 | errorMsg(); 305 | return this.capture('./capture/error.png'); 306 | }); 307 | } 308 | if (objStep.confirmtxt) { 309 | this.waitForText(objStep.confirmtxt, function() { 310 | return this.echo('Found confirm text: ' + objStep.confirmtxt); 311 | }, function() { 312 | this.echo('Confirm text' + objStep.confirmtxt + 'not found', 'ERROR'); 313 | errorMsg(); 314 | return this.capture('./capture/error.png'); 315 | }); 316 | } 317 | } else { 318 | this.echo('DOM selector not found', 'ERROR'); 319 | errorMsg(); 320 | } 321 | } 322 | if (objStep.command === 'wait') { 323 | this.echo('Waiting for ' + objStep.value + ' ms'); 324 | this.wait(objStep.value, function() { 325 | this.echo('Finished wait time.'); 326 | }); 327 | } 328 | if (objStep.command === 'title') { 329 | if (objStep.selector) { 330 | tempObj = objStep.selector; 331 | } else if (objStep.xpath) { 332 | tempObj = { 333 | type: 'xpath', 334 | path: objStep.xpath 335 | }; 336 | } 337 | if (this.exists(tempObj)) { 338 | this.sendKeys(tempObj, submitArticle.title); 339 | this.echo('Entered title'); 340 | } else { 341 | this.echo('Input field not found', 'ERROR'); 342 | errorMsg(); 343 | } 344 | } 345 | if (objStep.command === 'backlinks') { 346 | if (objStep.selector) { 347 | tempObj = objStep.selector; 348 | } else if (objStep.xpath) { 349 | tempObj = { 350 | type: 'xpath', 351 | path: objStep.xpath 352 | }; 353 | } 354 | if (this.exists(tempObj)) { 355 | this.sendKeys(tempObj, backlinksList); 356 | this.echo('Entered backlinks list'); 357 | } else { 358 | this.echo('Input field not found', 'ERROR'); 359 | errorMsg(); 360 | } 361 | } 362 | if (objStep.command === 'body') { 363 | if (objStep.selector) { 364 | tempObj = objStep.selector; 365 | } else if (objStep.xpath) { 366 | tempObj = { 367 | type: 'xpath', 368 | path: objStep.xpath 369 | }; 370 | } 371 | if (this.exists(tempObj)) { 372 | this.sendKeys(tempObj, submitArticle.body); 373 | this.echo('Entered body'); 374 | } else { 375 | this.echo('Input field not found', 'ERROR'); 376 | errorMsg(); 377 | } 378 | } 379 | if (objStep.command === 'save-href') { 380 | if (objStep.selector) { 381 | tempObj = objStep.selector; 382 | } else if (objStep.xpath) { 383 | tempObj = { 384 | type: 'xpath', 385 | path: objStep.xpath 386 | }; 387 | } 388 | if (this.exists(tempObj)) { 389 | submitURL = this.getElementAttribute(tempObj, 'href'); 390 | backlinksList += submitURL + '\n'; 391 | consolex.log('cyan', 'Submitted post to URL: ' + submitURL); 392 | try { 393 | fs.write(fileBacklinks, submitURL, 'a'); 394 | fs.write(fileBacklinks, '\n', 'a'); 395 | } catch (e) { 396 | this.echo(e); 397 | } 398 | return this.echo('Saved backlink to ' + fileBacklinks); 399 | } else { 400 | this.echo('DOM selector not found' + tempObj, 'ERROR'); 401 | return errorMsg(); 402 | } 403 | } 404 | }; 405 | 406 | casper.start(); 407 | 408 | casper.repeat(numLoops, function() { 409 | return this.then(function() { 410 | var objStep, serviceName; 411 | if (currentService >= service.length) { 412 | ++currentSubmission; 413 | currentService = 0; 414 | currentStep = 0; 415 | } 416 | if (currentSubmission < numPosts) { 417 | serviceName = service[currentService].name; 418 | objStep = service[currentService].steps[currentStep]; 419 | this.doStep(objStep, serviceName); 420 | this.then(function() { 421 | this.capture('./capture/capture' + currentStep + '.png'); 422 | ++currentStep; 423 | if (currentStep === service[currentService].steps.length) { 424 | serviceName = service[currentService].name; 425 | consolex.log('green', 'Completed submit to ' + serviceName + '\n'); 426 | ++currentService; 427 | return currentStep = 0; 428 | } 429 | }); 430 | return; 431 | } 432 | }); 433 | }); 434 | 435 | casper.then(function() { 436 | return consolex.log('blue', 'Submitting links to indexeing services'); 437 | }); 438 | 439 | casper.repeat(numIndexerLoops, function() { 440 | return this.then(function() { 441 | var objStep, serviceName; 442 | if (currentIndexer < indexers.length) { 443 | serviceName = indexers[currentIndexer].name; 444 | objStep = indexers[currentIndexer].steps[currentIndexerStep]; 445 | this.doStep(objStep, serviceName); 446 | ++currentIndexerStep; 447 | if (currentIndexerStep === indexers[currentIndexer].steps.length) { 448 | ++currentIndexer; 449 | return currentIndexerStep = 0; 450 | } 451 | } 452 | }); 453 | }); 454 | 455 | casper.run(function() { 456 | consolex.log('green', 'Finished all submissions.'); 457 | this.echo('Press ctrl C to exit'); 458 | this.exit(0); 459 | this.bypass(1); 460 | }); 461 | 462 | }).call(this); 463 | --------------------------------------------------------------------------------