Files
A69WD/Src/A69WD/Net/cLink_A69.cs
T

1070 lines
53 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Remoting.Messaging;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using A69WD.Data;
using A69WD.Service;
using HtmlAgilityPack;
namespace A69WD.Net {
public class cLink_A69 : iLink {
public static string PageBase { get { return "https://www.annunci69.it"; } }
public static string LoginPageUrl { get { return "https://www.annunci69.it/accedi.php"; } }
public static string LoginPostUrl { get { return "https://www.annunci69.it/include/auth/index.php"; } }
public static string LinkIdxBase { get { return "https://www.annunci69.it/racconti-erotici/racconti_lista.php?genere={Categoria}&pagina={ID}"; } }
public string[] Categorie { get { return Categorie; } }
private static readonly string[] categorie = { "altro", "bdsm", "gay", "incesto", "lesbo", "orge", "prime", "scambio", "tradimenti", "trans", "trio" };
private readonly string filename;
private readonly string filepath;
private eLinkState status = eLinkState.ToConfirm;
private string fields;
public string ID => "A69";
public string URL { get; }
public string FileName => filename;
public string FilePath { get => filepath; }
public bool Validate {
get {
if (URL.StartsWith("https://www.annunci69.it/racconti-erotici/racconti_lista.php?genere=")) {
// URL di tipo Idx, devo lavorare i link nuovo o rilavorare i link più obsoleti di 6 ore.
return !App.DB.IsPresent(URL, -6);
} else {
// URL di tipo Rac, devo lavorare solo i link nuovi
return !App.DB.IsPresent(URL);
}
}
}
public eLinkState Status { get => status; set { status = value; } }
public string Fields { get => fields; set => fields = value; }
public cLink_A69(string Url, string Filename, string fields = "none", string Filepath = "") {
this.URL = Url;
this.filename = Filename;
this.fields = fields;
this.filepath = string.IsNullOrEmpty(Filepath) ? Cfg.Settings.PathDownloadWorking : Filepath;
this.status = eLinkState.ToConfirm;
}
public static List<iLink> GetStartLink() {
List<iLink> links = new List<iLink>();
for (int i = 0; i < 10; i++) {
foreach (string cat in categorie) {
string url = LinkIdxBase.Replace("{Categoria}", cat).Replace("{ID}", i.ToString());
string name = string.Format("_A69_{0}_{1}.html", cat, i.ToString());
links.Add(new cLink_A69(url, name));
}
}
return links;
}
public static bool InsertStartLink(BlockingCollection<iLink> _urlQueue) {
int i = 1;
try {
foreach (string cat in categorie) {
string url = LinkIdxBase.Replace("{Categoria}", cat).Replace("{ID}", i.ToString());
string name = string.Format("_A69_{0}_{1}.html", cat, i.ToString("0000"));
_urlQueue.Add(new cLink_A69(url, name));
}
return true;
} catch (Exception ex) {
Logger.Error("Errore inserendo A69 Start Link - " + ex.Message);
return false;
}
}
public static bool InsertStartLink(Service_Crawler service) {
//string url = LinkIdxBase.Replace("{Categoria}", "altro").Replace("{ID}", "1"); //LinkIdxBase.Replace("{Categoria}", "trio").Replace("{ID}", "1");
//string name = "_A69_altro_0001.html"; //"_A69_trio_0001.html";
//serviceCrawler.EnqueueUrl(new cLink_A69(url, name));
//return true;
int i = 1;
try {
foreach (string cat in categorie) {
string url = LinkIdxBase.Replace("{Categoria}", cat).Replace("{ID}", i.ToString());
string name = string.Format("_A69_{0}_{1}.html", cat, i.ToString("0000"));
service.EnqueueUrl(new cLink_A69(url, name));
}
return true;
} catch (Exception ex) {
Logger.Error("Errore inserendo A69 Start Link - " + ex.Message);
return false;
}
}
public async Task<cRac> EstraiRac(string FileFullPath) {
/*
* Analisi html dei racconti aggiornata al 2025/12/27:
*
*
* Per ciascun file html, si ha un unico racconto che ha un formato interno pari a:
* <html xmlns="http://www.w3.org/1999/xhtml">
* <body>
* ...
* <div class="targhetta_racconti" style=" width:100%; background-color:#5d5d5d;">incesto</div>
* ...
* <h1 class="titolone_nero" ...>Mia Madre , La mia Amante</h1>
* <strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;di<a href="/user/Bambino">Bambino</a>
* ...
* <div style="float:left; margin-right:5px; color: #9999CC; ">
* <span class="text_grigio" style="line-height:1.6em; color: #9999CC; font-size:13px;">&nbsp;<strong>Scritto il</strong> 22.08.2015 &nbsp;&nbsp; | &nbsp;&nbsp;
* <strong>Letture:</strong> 8.947&nbsp;&nbsp;| &nbsp;&nbsp;
* <strong>Votazione 8.0:</strong></span>
* </div>
* ...
* <div class="testoracc" style="color:#666666; text-align:justify; padding:20px 20px 0px 0px;">
* Eliminare i DIV interni che hanno cose grafiche
* Il testo è quello che rimane.
* </div>
* </body>
* </html>
*
* quindi i dati del racconto che si possono estrapolare sono:
* Titolo: --> Testo del nodo <h1 class="titolone_nero">
* SubTitle: --> Sempre Vuoto
* Autore: --> Testo del nodo <strong><a>
* Creato: --> Estrarre la parte dal <div style="float:left; margin-right:5px; color: #9999CC; ">
* Tags: --> Testo del nodo div class="targhetta_racconti">
* Trama: --> Testo del nodo <div class="testoracc"> a cui si levano i DIV interni.
* Notes: --> SrcFile - Nome del file che si analizza
* Origini: --> Sempre l'ID della sorgente web
* Voto: --> Sempre "Non Letto"
* Updated: --> Data attuale
*
*/
cRac rac = new cRac();
HtmlNodeCollection nodes;
try {
Console.WriteLine($"A69 - Importo: {FileFullPath}");
string filePathName = System.IO.Path.GetFileName(FileFullPath);
// Ricavo il nodo radice del racconto:
HtmlDocument tdoc = new HtmlDocument();
tdoc.Load(FileFullPath);
HtmlNode root = tdoc.DocumentNode;
if (root == null) {
// racconto non presente
return null;
}
#region Origini: --> Sempre l'ID della sorgente web
rac.Origini = new List<string> { ID };
#endregion
#region Titolo: --> Testo del nodo <h1 class="titolone_nero">
try {
nodes = root.SelectNodes("//h1[@class='titolone_nero']");
rac.Title = cTools.FormattaTesto(nodes[0].InnerText.Trim(), false);
if (string.IsNullOrEmpty(rac.Title)) {
Logger.Error($"A69 - Import - No Title - {filePathName}");
return null;
}
} catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione titolo dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region SubTitle: --> Sempre Vuoto
rac.SubTitle = "";
#endregion
#region Autore: --> Testo del nodo <strong><a>
try {
// Autore --> Testo del nodo <span class="text_grigio><a>"
nodes = root.SelectNodes("//span[@class='text_grigio']//a");
List<string> items = new List<string>();
foreach (HtmlNode nd in nodes) {
string aut = nd.ParentNode.InnerText.Replace("&nbsp;", "").Trim();
if (aut.StartsWith("di")) {
items.Add(aut.Replace("di", "").Trim());
}
}
items.Sort();
string tmp = "";
rac.Autori = new List<string>();
// Rimuovo eventuali duplicati
foreach (string aut in items) {
if (tmp != aut) {
rac.Autori.Add(aut);
tmp = aut;
}
}
if (rac.Autori == null || string.IsNullOrEmpty(rac.Autori[0])) {
Logger.Error($"A69 - Import - No Autors - {filePathName}");
return null;
}
} catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione autore dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Creato: --> Estrarre la parte dal <div style="float:left; margin-right:5px; color: #9999CC; ">
rac.Creato = DateTime.Now;
try {
// Creato --> Estrarre la prima parte dal <span class="text_grigio"> che ha il testo "Data|Visite|Commenti":
nodes = root.SelectNodes("//span[@class='text_grigio']");
foreach (HtmlNode nd in nodes) {
string txt = nd.InnerText.Trim().Replace("&nbsp;", "");
string[] parts = txt.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 3) {
CultureInfo culture = CultureInfo.CreateSpecificCulture("it-IT");
DateTimeStyles styles = DateTimeStyles.None;
DateTime tmpDT = DateTime.Now;
if (!DateTime.TryParse(parts[0].Trim(), culture, styles, out tmpDT)) {
Logger.Error($"A69 - Import - No data - {filePathName}");
}
rac.Creato = tmpDT;
}
}
} catch (Exception ex) { Logger.Warning(string.Format("Data non riconosciuta nel file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Updated: --> Data attuale
rac.Updated = DateTime.Now;
#endregion
#region Tags: --> Testo del nodo div class="targhetta_racconti">
try {
nodes = root.SelectNodes("//div[@class='targhetta_racconti']");
List<string> items = new List<string>();
foreach (HtmlNode nd in nodes) {
items.Add(cTools.FormattaTesto(nd.InnerText.Replace("genere", "").Trim(), false));
}
//items.Sort();
items = items
.OrderBy(s => s) // ordina alfabeticamente
.Distinct() // elimina duplicati
.ToList();
Format_Insert_Tags(rac, items); // rac.Tags = items;
} catch (Exception ex) { Logger.Warning(string.Format("Fallita estrazione Tags dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Trama: --> Testo del nodo <div class="testoracc"> a cui si levano i DIV interni.
try {
nodes = root.SelectNodes("//div[@class='testoracc']");
foreach (HtmlNode nd in nodes) {
foreach (HtmlNode n in nd.ChildNodes) {
if (n.Name.ToUpper() == "#TEXT") { rac.Trama += cTools.FormattaTesto(n.InnerText.Trim(), false); }
if (n.Name.ToUpper() == "BR") { rac.Trama += "\r"; }
if (n.Name.ToUpper() == "DIV") {; }
}
}
} catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione Trama dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Voto: --> Sempre "Non Letto"
rac.Voto = "Non Letto";
#endregion
#region Notes: --> SrcFile - Nome del file che si analizza
rac.Notes = new List<Data.cNota>();
rac.Notes.Add(new Data.cNota("SrcFile", System.IO.Path.GetFileName(filePathName)));
#endregion
// Formalizzo esito estrazione:
if (!rac.Validate()) {
rac = null;
}
} catch (Exception ex) {
Logger.Error($"A69 - Import Error - {FileFullPath}: {ex.Message}");
Console.WriteLine($"A69 - Import Error - {FileFullPath}: {ex.Message}");
return null;
}
return rac;
}
public cRac EstraiRac(HtmlDocument doc) {
/*
* Analisi html dei racconti aggiornata al 2025/12/27:
*
*
* Per ciascun file html, si ha un unico racconto che ha un formato interno pari a:
* <html xmlns="http://www.w3.org/1999/xhtml">
* <body>
* ...
* <div class="targhetta_racconti" style=" width:100%; background-color:#5d5d5d;">incesto</div>
* ...
* <h1 class="titolone_nero" ...>Mia Madre , La mia Amante</h1>
* <strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;di<a href="/user/Bambino">Bambino</a>
* ...
* <div style="float:left; margin-right:5px; color: #9999CC; ">
* <span class="text_grigio" style="line-height:1.6em; color: #9999CC; font-size:13px;">&nbsp;<strong>Scritto il</strong> 22.08.2015 &nbsp;&nbsp; | &nbsp;&nbsp;
* <strong>Letture:</strong> 8.947&nbsp;&nbsp;| &nbsp;&nbsp;
* <strong>Votazione 8.0:</strong></span>
* </div>
* ...
* <div class="testoracc" style="color:#666666; text-align:justify; padding:20px 20px 0px 0px;">
* Eliminare i DIV interni che hanno cose grafiche
* Il testo è quello che rimane.
* </div>
* </body>
* </html>
*
* quindi i dati del racconto che si possono estrapolare sono:
* Titolo: --> Testo del nodo <h1 class="titolone_nero">
* SubTitle: --> Sempre Vuoto
* Autore: --> Testo del nodo <strong><a>
* Creato: --> Estrarre la parte dal <div style="float:left; margin-right:5px; color: #9999CC; ">
* Tags: --> Testo del nodo div class="targhetta_racconti">
* Trama: --> Testo del nodo <div class="testoracc"> a cui si levano i DIV interni.
* Notes: --> SrcFile - Nome del file che si analizza
* Origini: --> Sempre l'ID della sorgente web
* Voto: --> Sempre "Non Letto"
* Updated: --> Data attuale
*
*/
cRac rac = new cRac();
HtmlNodeCollection nodes;
try {
Console.WriteLine($"A69 - Importo: {FileName}");
// Ricavo il nodo radice del racconto:
HtmlNode root = doc.DocumentNode;
if (root == null) {
// racconto non presente
return null;
}
#region Origini: --> Sempre l'ID della sorgente web
rac.Origini = new List<string> { ID };
#endregion
#region Titolo: --> Testo del nodo <h1 class="titolone_nero">
try {
nodes = root.SelectNodes("//h1[@class='titolone_nero']");
rac.Title = cTools.FormattaTesto(nodes[0].InnerText.Trim(), false);
if (string.IsNullOrEmpty(rac.Title)) {
Logger.Error($"A69 - Import - No Title - {FileName}");
return null;
}
} catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione titolo dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region SubTitle: --> Sempre Vuoto
rac.SubTitle = "";
#endregion
#region Autore: --> Testo del nodo <strong><a>
try {
// Autore --> Testo del nodo <span class="text_grigio><a>"
nodes = root.SelectNodes("//span[@class='text_grigio']//a");
List<string> items = new List<string>();
foreach (HtmlNode nd in nodes) {
string aut = nd.ParentNode.InnerText.Replace("&nbsp;", "").Trim();
if (aut.StartsWith("di")) {
items.Add(aut.Replace("di", "").Trim());
}
}
items.Sort();
string tmp = "";
rac.Autori = new List<string>();
// Rimuovo eventuali duplicati
foreach (string aut in items) {
if (tmp != aut) {
rac.Autori.Add(aut);
tmp = aut;
}
}
if (rac.Autori == null || string.IsNullOrEmpty(rac.Autori[0])) {
Logger.Error($"A69 - Import - No Autors - {FileName}");
return null;
}
} catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione autore dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Creato: --> Estrarre la parte dal <div style="float:left; margin-right:5px; color: #9999CC; ">
rac.Creato = DateTime.Now;
try {
// Creato --> Estrarre la prima parte dal <span class="text_grigio"> che ha il testo "Data|Visite|Commenti":
nodes = root.SelectNodes("//span[@class='text_grigio']");
foreach (HtmlNode nd in nodes) {
string txt = nd.InnerText.Trim().Replace("&nbsp;", "");
string[] parts = txt.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 3) {
CultureInfo culture = CultureInfo.CreateSpecificCulture("it-IT");
DateTimeStyles styles = DateTimeStyles.None;
DateTime tmpDT = DateTime.Now;
if (!DateTime.TryParse(parts[0].Trim(), culture, styles, out tmpDT)) {
Logger.Error($"A69 - Import - No data - {FileName}");
}
rac.Creato = tmpDT;
}
}
} catch (Exception ex) { Logger.Warning(string.Format("Data non riconosciuta nel file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Updated: --> Data attuale
rac.Updated = DateTime.Now;
#endregion
#region Tags: --> Testo del nodo div class="targhetta_racconti">
try {
nodes = root.SelectNodes("//div[@class='targhetta_racconti']");
List<string> items = new List<string>();
foreach (HtmlNode nd in nodes) {
items.Add(cTools.FormattaTesto(nd.InnerText.Replace("genere", "").Trim(), false));
}
//items.Sort();
items = items
.OrderBy(s => s) // ordina alfabeticamente
.Distinct() // elimina duplicati
.ToList();
Format_Insert_Tags(rac, items); // rac.Tags = items;
} catch (Exception ex) { Logger.Warning(string.Format("Fallita estrazione Tags dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Trama: --> Testo del nodo <div class="testoracc"> a cui si levano i DIV interni.
try {
nodes = root.SelectNodes("//div[@class='testoracc']");
foreach (HtmlNode nd in nodes) {
foreach (HtmlNode n in nd.ChildNodes) {
if (n.Name.ToUpper() == "#TEXT") { rac.Trama += cTools.FormattaTesto(n.InnerText.Trim(), false); }
if (n.Name.ToUpper() == "BR") { rac.Trama += "\r"; }
if (n.Name.ToUpper() == "DIV") {; }
}
}
} catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione Trama dal file {0}\r\n{1}", FileName, ex.Message)); return null; }
#endregion
#region Voto: --> Sempre "Non Letto"
rac.Voto = "Non Letto";
#endregion
#region Notes: --> SrcFile - Nome del file che si analizza
rac.Notes = new List<Data.cNota>();
rac.Notes.Add(new Data.cNota("SrcFile", System.IO.Path.GetFileName(FileName)));
#endregion
// Formalizzo esito estrazione:
if (!rac.Validate()) {
rac = null;
}
} catch (Exception ex) {
Logger.Error($"A69 - Import Error - {FileName}: {ex.Message}");
Console.WriteLine($"A69 - Import Error - {FileName}: {ex.Message}");
return null;
}
return rac;
}
protected virtual void Format_Insert_Tags(Data.cRac rac, List<string> items) {
// Per ora riporto tutti i tag rilevati, mentre in futuro dovrò:
// - parsare la lista e formattare correttamente i tag
// - ordinare la lista dei tag formattati ed eliminare i duplicati
// - se non sono rimasti tag, inserisco il tag generale per indicare che non vi sono tag
// - altrimenti inserisco tutti i tag rimasti.
rac.Tags = new List<string>();
try {
items.Sort();
string tmp = "";
foreach (string item in items) {
string it = item.Trim().ToLower();
if (tmp != it) {
#region switch per formattare il testo
switch (it) {
//case "racconti 69":
// rac.Tags.Add("69");
// break;
//case "abusi":
// rac.Tags.Add("Abusi");
// break;
//case "camgirl":
//case "chat e siti di incontri…":
//case "fiche":
// rac.Tags.Add("Altro");
// break;
//case "amatoriali":
// rac.Tags.Add("Amatoriali");
// break;
//case "anale":
// rac.Tags.Add("Anale");
// break;
//case "audio libri erotici":
//case "audio racconti erotici":
// rac.Tags.Add("Audio");
// break;
//case "bdsm":
// rac.Tags.Add("BDMS");
// break;
//case "bisex":
//case "bisex ♀":
//case "bisex ♂":
// rac.Tags.Add("Bisex");
// break;
//case "bondage":
// rac.Tags.Add("Bondage");
// break;
//case "bondage e sadomaso":
// rac.Tags.Add("Bondage");
// rac.Tags.Add("Sadomaso");
// break;
//case "bukkake":
// rac.Tags.Add("Bukkake");
// break;
//case "comici":
//case "comunità":
// rac.Tags.Add("Comico");
// break;
//case "concorso estate 2019":
//case "concorso natale 2018":
//case "decameron 2020":
// rac.Tags.Add("Concorso");
// break;
//case "confessioni":
// rac.Tags.Add("Confessioni");
// break;
//case "coppie":
//case "scambio di coppia":
//case "scambio di coppie":
// rac.Tags.Add("Coppie");
// break;
//case "cuckold":
//case "racconti cuckold":
// rac.Tags.Add("Cuckold");
// break;
//case "curiosità":
//case "curiosità sul sesso":
// rac.Tags.Add("Curiosità");
// break;
//case "dominazione":
//case "racconti di dominazione":
//case "schiavi&amp;padroni":
// rac.Tags.Add("Dominazione");
// break;
//case "doppia penetrazione":
// rac.Tags.Add("Doppia Penetrazione");
// break;
//case "esibizionismo":
// rac.Tags.Add("Esibizionismo");
// break;
//case "etero":
//case "lui & lei":
//case "racconti erotici etero":
// rac.Tags.Add("Etero");
// break;
//case "feticismo":
// rac.Tags.Add("Feticismo");
// break;
//case "fisting":
// rac.Tags.Add("Fisting");
// break;
//case "gang bang":
// rac.Tags.Add("Gang Bang");
// break;
//case "gay":
//case "racconti gay":
// rac.Tags.Add("Gay");
// break;
//case "gay & bisex":
//case "gay e bisex":
// rac.Tags.Add("Gay");
// rac.Tags.Add("Bisex");
// break;
//case "gay - travestiti":
// rac.Tags.Add("Gay");
// rac.Tags.Add("Trans");
// break;
//case "incesti":
//case "incesto":
//case "racconti erotici sull'incesto":
// rac.Tags.Add("Incesto");
// break;
//case "interviste":
//case "interviste erotiche":
// rac.Tags.Add("Intervista");
// break;
//case "lesbo":
//case "racconti erotici lesbo":
//case "saffico":
// rac.Tags.Add("Lesbo");
// break;
//case "autoerotismo":
//case "masturbazione":
//case "masturbazioni":
//case "racconti sull'autoerotismo":
// rac.Tags.Add("Masturbazione");
// break;
//case "milf":
// rac.Tags.Add("MILF");
// break;
//case "nudismo":
// rac.Tags.Add("Nudismo");
// break;
//case "orge":
//case "orgia":
//case "sesso di gruppo":
// rac.Tags.Add("Orge");
// break;
//case "pissing":
// rac.Tags.Add("Pissing");
// break;
//case "lirica erotica":
//case "poesia erotica":
//case "poesie":
//case "poesie erotiche":
// rac.Tags.Add("Poesia");
// break;
//case "pompini":
// rac.Tags.Add("Pompini");
// break;
//case "giochi erotici":
//case "prime esperienze":
//case "prime volte":
// rac.Tags.Add("Prime Esperienze");
// break;
//case "pulp":
// rac.Tags.Add("Pulp");
// break;
//case "sadomaso":
// rac.Tags.Add("Sadomaso");
// break;
//case "sensazioni":
//case "sentimentali":
// rac.Tags.Add("Sentimentali");
// break;
//case "cornuti":
//case "tradimenti":
//case "tradimento":
// rac.Tags.Add("Tradimento");
// break;
//case "racconti con trans":
//case "racconti trans":
//case "trans":
//case "trans e travestiti":
// rac.Tags.Add("Trans");
// break;
//case "trasgressivo":
// rac.Tags.Add("Trasgressivo");
// break;
//case "trio":
// rac.Tags.Add("Trio");
// break;
//case "uncategorized":
// rac.Tags.Add("Uncategorized");
// break;
//case "voyeur":
//case "voyeurismo":
// rac.Tags.Add("Voyeur");
// break;
//case "animali":
//case "zoofilia":
// rac.Tags.Add("Zoofilia");
// break;
//case "Gay":
// rac.Tags.Add("Gay");
// break;
//case "Racconti bisex":
// rac.Tags.Add("Bisex");
// break;
//case "Racconti etero":
// rac.Tags.Add("Etero");
// break;
//case "Racconti fetish":
// rac.Tags.Add("Feticismo");
// break;
//case "Racconti incesto":
// rac.Tags.Add("Incesto");
// break;
//case "Racconti lesbo":
// rac.Tags.Add("Lesbo");
// break;
//case "Racconti masturbazione":
// rac.Tags.Add("Masturbazione");
// break;
//case "Racconti mature":
// rac.Tags.Add("Mature");
// break;
//case "Racconti orge":
// rac.Tags.Add("Orge");
// break;
//case "Racconti prima volta":
// rac.Tags.Add("Prime Esperienze");
// break;
//case "Racconti ricatto":
// rac.Tags.Add("Ricatto");
// break;
//case "Racconti scambio di coppia":
// rac.Tags.Add("Coppie");
// break;
//case "Racconti sottomissione":
// rac.Tags.Add("Dominazione");
// break;
//case "Racconti tradimenti":
// rac.Tags.Add("Tradimento");
// break;
//case "Racconti trav":
//case "Trans":
// rac.Tags.Add("Trans");
// break;
default:
rac.Tags.Add(item);
break;
}
#endregion
tmp = it;
}//if
}//foreach
} catch (Exception ex) {
Logger.Error(string.Format("Error Code: {0} - Errore in {1}.{2}: {3}", "ER00040", System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType.FullName, System.Reflection.MethodInfo.GetCurrentMethod().Name, ex.Message));
} finally {
if (rac.Tags.Count == 0) rac.Tags.Add("_None_");
}
}//function
#region Gestione Sito A69
private static HttpClient client = null;
private static readonly string nickname = @"Toky78";
private static readonly string password = @"p!fw05Q9Hc6j5";
private static bool autenticated = false;
/// <summary>
/// Indica se siamo autenticati al sito
/// </summary>
public static bool Autenticated => autenticated;
/// <summary>
/// Esegue l'autenticazione al sito:
/// - Scarica la pagina di autenticazione
/// - analizza quanto scaricato per determinare i campi dinamici 'ts' e 'token'
/// - prepara la risposta al form di identificazione
/// - invia il POST di autenticazione
/// - analizza la risposta per verificare il corretto login
/// </summary>
public static async Task<bool> Authenticate() {
if (autenticated) {
// Autenticazione già fatta, posso proseguire senza altro fare
Logger.Warning("A69 - Autenticazione già effettuata.");
}
try {
#region 1) Prepare HTML Client
HttpClientHandler _handler = new HttpClientHandler {
CookieContainer = new CookieContainer(),
UseCookies = true,
AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
client = new HttpClient(_handler);
client.Timeout = TimeSpan.FromSeconds(60);
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
client.DefaultRequestHeaders.Referrer = new Uri(cLink_A69.LoginPageUrl);
#endregion
#region 2) GET pagina di login
Console.WriteLine("A69 - Richiedo la pagina di login...");
Logger.Information("A69 - Richiedo la pagina di login...");
string loginPageHtml = await client.GetStringAsync(cLink_A69.LoginPageUrl);
#endregion
#region 3) Parsing HTML per estrarre ts e token
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(loginPageHtml);
string ts = doc.DocumentNode
.SelectSingleNode("//input[@name='ts']")
?.GetAttributeValue("value", "");
string token = doc.DocumentNode
.SelectSingleNode("//input[@name='token']")
?.GetAttributeValue("value", "");
if (string.IsNullOrWhiteSpace(ts) || string.IsNullOrWhiteSpace(token)) {
Console.WriteLine("A69 - Impossibile estrarre 'ts' o 'token' dalla pagina di login.");
Logger.Information("A69 - Impossibile estrarre 'ts' o 'token' dalla pagina di login.");
return autenticated;
}
Console.WriteLine($"A69 - Parametri dinamici trovati: ts={ts}, token={token}");
Logger.Information($"A69 - Parametri dinamici trovati: ts={ts}, token={token}");
#endregion
#region 4) POST login con valori dinamici
var loginData = new FormUrlEncodedContent(new[] {
new KeyValuePair<string,string>("nick", nickname),
new KeyValuePair<string,string>("pwd", password),
new KeyValuePair<string,string>("ricordami","1"),
new KeyValuePair<string,string>("login", "Entra"),
new KeyValuePair<string,string>("ts", ts),
new KeyValuePair<string,string>("token", token)
});
Console.WriteLine("Invio credenziali di login...");
var loginResponse = await client.PostAsync(cLink_A69.LoginPostUrl, loginData);
if (!loginResponse.IsSuccessStatusCode) {
Console.WriteLine($"A69 - Login fallito. HTTP {(int)loginResponse.StatusCode} {loginResponse.ReasonPhrase}");
Logger.Information($"A69 - Login fallito. HTTP {(int)loginResponse.StatusCode} {loginResponse.ReasonPhrase}");
return autenticated;
}
#endregion
#region 5) Verifica autenticazione correttamente avvenuta
// Verifica semplice: sulla pagina di login effettuato, ricerco il nome dell'utente:
string loginResult = await loginResponse.Content.ReadAsStringAsync();
if (loginResult.Contains(nickname)) {
Console.WriteLine("A69 - Login effettuato con successo! Sessione autenticata attiva.");
Logger.Information("A69 - Login effettuato con successo! Sessione autenticata attiva.");
autenticated = true;
} else {
Console.WriteLine("A69 - Login non riuscito: il server ha restituito un messaggio di errore.");
Logger.Information("A69 - Login non riuscito: il server ha restituito un messaggio di errore.");
autenticated = false;
}
#endregion
} catch (Exception ex) {
Console.WriteLine($"Errore generale: {ex.Message}");
Logger.Information($"Errore generale: {ex.Message}");
}
return autenticated;
}
/// <summary>
/// Codice da eseguire per ciascun A69 link:
/// - scarico l'url indicato
/// - se richiesto lo salvo come file di testo
/// - analizzo il documento html ed estraggo tutti gli url ad altre pagine di link
/// - analizzo il documento html ed estraggo tutti gli url a racconti
/// - analizzo il documento html ed estraggo il testo del racconto
/// </summary>
/// <param name="lk"></param>
/// <returns></returns>
public async Task<List<iLink>> CrawlPageAsync() {
var newlinks = new List<iLink>();
try {
Console.WriteLine($"A69 - Scarico: {URL}");
HtmlDocument tdoc = null;
string thtml = "";
#region ToConfirm
if (Status == eLinkState.ToConfirm) {
// Eseguo la verifica se link da downloadare
Status = eLinkState.ToDownload;
}
#endregion
#region ToDownload
if (Status == eLinkState.ToDownload) {
Status = eLinkState.OnDownload;
}
#endregion
#region OnDownload
if (Status == eLinkState.OnDownload) {
// Scarico il file
var resp = await client.GetAsync(URL);
if (!resp.IsSuccessStatusCode) {
Console.WriteLine($"A69 - Errore HTTP {(int)resp.StatusCode} {resp.ReasonPhrase} per {URL}");
Status = eLinkState.Error;
//App.DB.LinkLog(lk);
return newlinks;
}
// Scarico la pagina
thtml = await client.GetStringAsync(URL);
tdoc = new HtmlDocument();
tdoc.LoadHtml(thtml);
// Salvo il file downloadato
//SaveToFile(thtml, lk.FilePath, lk.FileName);
Status = eLinkState.ToAnalize;
}
#endregion
#region ToAnalize
{
if (Status == eLinkState.ToAnalize) {
List<string> tmpLk = new List<string>();
#region Estraggo gli url ad indici:
{
/*
* Gli url delle pagine di indice sono del tipo:
*
* <div id="pagination">
* <ul>
* <li class="prev"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=2">&lsaquo;</a></li>
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=1">1</a></li>
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=2">2</a></li>
* <li class="currentpage">3</li>
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=4">4</a></li>
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=5">5</a></li>
* <li class="next"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=4">&rsaquo;</a></li>
* </ul>
* </div>
*
*/
try {
// Estraggo i link alle altre pagine:
var tnodes = tdoc.DocumentNode.SelectNodes("//div[@id='pagination']//ul//li//a[@href]");
if (tnodes != null) {
foreach (var link in tnodes) {
var href = link.GetAttributeValue("href", "");
if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconti-erotici/racconti_lista.php?genere="))
tmpLk.Add(href); //tmpLk.Add(cLink_A69.PageBase + href);
}
}
// Rimuove duplicati e ordina alfabeticamente
tmpLk = tmpLk
.OrderBy(s => s) // ordina alfabeticamente
.Distinct() // elimina duplicati
.ToList();
// Inserisco i link trovati
foreach (string ilk in tmpLk) {
string[] separator = new string[] { "&pagina=" };
string[] txt = ilk.Split(separator, StringSplitOptions.RemoveEmptyEntries);
string url = cLink_A69.PageBase + ilk;
string name = txt[0].Replace("/racconti-erotici/racconti_lista.php?genere=", "_A69_") + "_" + int.Parse(txt[1]).ToString("0000") + ".html";
newlinks.Add(new cLink_A69(url, name));
}
} catch (Exception ex) {
Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message);
cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName);
}
}
#endregion
#region Estraggo gli url a racconti:
{
/*
*
* I link ai racconti sono dei pulsanti così formati:
* <div class="continua">
* <a href="/racconti-erotici/altro/Tutto-e-iniziato-per-gioco-pazza-famiglia_166770.html">Continua a leggere » </a>
* </div>
*/
try {
// Estraggo i link ai racconti:
tmpLk = new List<string>();
// Estraggo i link alle altre pagine:
var tnodes = tdoc.DocumentNode.SelectNodes("//div[@class='continua']//a[@href]");
if (tnodes != null) {
foreach (var link in tnodes) {
var href = link.GetAttributeValue("href", "");
if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconti-erotici/") && (href.EndsWith(".html") || href.EndsWith(".htm")))
tmpLk.Add(href); //tmpLk.Add(cLink_A69.PageBase + href);
}
}
// Rimuove duplicati e ordina alfabeticamente
tmpLk = tmpLk
.OrderBy(s => s) // ordina alfabeticamente
.Distinct() // elimina duplicati
.ToList();
// Inserisco i link trovati
foreach (string ilk in tmpLk) {
string url = cLink_A69.PageBase + ilk;
string name = ilk.Replace("/racconti-erotici/", "A69_").Replace(@"/", "_");
newlinks.Add(new cLink_A69(url, name));
}
} catch (Exception ex) {
Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message);
cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName);
}
}
#endregion
#region Estraggo il racconto dal file e lo inserisco nel DB
if (FileName.StartsWith("A69_")) {
// Link ad un racconto
cRac rac = EstraiRac(tdoc);
if (rac != null) {
// Racconto estratto correttamente, lo salvo sul DB
int res = App.DB.ImportRac(rac);
if (res > 0) {
// Racconto salvato correttamente sul DB
cTools.SaveToFile(thtml, Cfg.Settings.PathSrcDone, FileName);
} else {
// Errore nel salvataggio sul DB
cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnSave, FileName);
}
} else {
// Estrazione del racconto fallita
cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName);
}
} else {
// Link ad un indice
cTools.SaveToFile(thtml, Cfg.Settings.PathIdxDone, FileName);
}
#endregion
Status = eLinkState.End;
App.DB.LinkLog(this);
}
}
#endregion
#region End
if (Status == eLinkState.End) {
}
#endregion
#region Error
if (Status == eLinkState.Error) {
}
#endregion
#region Abort
if (Status == eLinkState.Abort) {
}
#endregion
#region Cancel
if (Status == eLinkState.Cancel) {
}
#endregion
Console.WriteLine("Link.Count=" + newlinks.Count.ToString("00"));
} catch (Exception ex) {
Console.WriteLine($"Errore con {URL}: {ex.Message}");
Status = eLinkState.Error;
App.DB.LinkLog(this);
}
return newlinks;
}
#endregion
}//class cLink_A69
}//namespace A69WD.Net