619 lines
21 KiB
Python
619 lines
21 KiB
Python
#
|
|
#CVIssueCount.py
|
|
#
|
|
#Author: Frederik Baerentsen
|
|
#
|
|
#Description: Complete Story Arc with the Comic Vine info
|
|
#
|
|
#Versions:
|
|
# V1 0.1 First version
|
|
# V2 0.2 Added Progressbar, start and cancel buttons
|
|
# V2 0.3 Added issue count
|
|
# V3 0.4 Added local database support
|
|
# V3 0.5 Added settings dialog (API key, local DB options, API delay)
|
|
# V3 1.0 Performance improvements and stability fixes
|
|
#
|
|
|
|
# $ cd "..\..\Program Files\ComicRack\
|
|
# $ ComicRack.exe -ssc
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import clr, re, sys, os, urlparse, time
|
|
|
|
from System.Diagnostics import Process
|
|
clr.AddReference("System.xml")
|
|
import System
|
|
from System import *
|
|
from System.IO import *
|
|
from System.Collections import *
|
|
from System.Threading import *
|
|
from System.Net import *
|
|
from System.Text import *
|
|
|
|
clr.AddReference('System')
|
|
clr.AddReference("System.Windows.Forms")
|
|
clr.AddReference("System.Drawing")
|
|
|
|
import System.Drawing
|
|
import System.Windows.Forms
|
|
|
|
from System.Drawing import *
|
|
from System.Windows.Forms import *
|
|
|
|
clr.AddReference('System.Drawing')
|
|
from System.Drawing import Point, Size, ContentAlignment, Color, SystemColors, Icon
|
|
clr.AddReference('System.Threading')
|
|
from System.Threading import *
|
|
from datetime import datetime
|
|
import ssl, urllib
|
|
from System.ComponentModel import BackgroundWorker
|
|
|
|
|
|
stop=False
|
|
|
|
# ============== Settings Management ==============
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
SETTINGS_FILE = os.path.join(SCRIPT_DIR, "CVIssueCount.ini")
|
|
|
|
class Settings:
|
|
def __init__(self):
|
|
self.api_key = ""
|
|
self.skip_api_if_not_in_db = False
|
|
self.always_use_api = False
|
|
self.api_delay = 10 # seconds between API calls, 0 to disable
|
|
self.load_from_file()
|
|
|
|
def load_from_file(self):
|
|
"""Load settings from INI file."""
|
|
if os.path.exists(SETTINGS_FILE):
|
|
try:
|
|
with open(SETTINGS_FILE, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if '=' in line:
|
|
key, value = line.split('=', 1)
|
|
key = key.strip()
|
|
value = value.strip()
|
|
if key == 'api_key':
|
|
self.api_key = value
|
|
elif key == 'skip_api_if_not_in_db':
|
|
self.skip_api_if_not_in_db = value.lower() == 'true'
|
|
elif key == 'always_use_api':
|
|
self.always_use_api = value.lower() == 'true'
|
|
elif key == 'api_delay':
|
|
try:
|
|
self.api_delay = int(value)
|
|
except:
|
|
self.api_delay = 10
|
|
except Exception as e:
|
|
print "Error loading settings: " + str(e)
|
|
|
|
def save_to_file(self):
|
|
"""Save settings to INI file."""
|
|
try:
|
|
with open(SETTINGS_FILE, 'w') as f:
|
|
f.write("api_key=" + self.api_key + "\n")
|
|
f.write("skip_api_if_not_in_db=" + str(self.skip_api_if_not_in_db).lower() + "\n")
|
|
f.write("always_use_api=" + str(self.always_use_api).lower() + "\n")
|
|
f.write("api_delay=" + str(self.api_delay) + "\n")
|
|
except Exception as e:
|
|
print "Error saving settings: " + str(e)
|
|
|
|
# Global settings instance
|
|
settings = Settings()
|
|
|
|
# ============== SQLite Initialization ==============
|
|
|
|
_sqlite_initialized = False
|
|
_sqlite_available = False
|
|
_SQLiteConnection = None
|
|
|
|
def _init_sqlite():
|
|
"""Initialize SQLite once at module load. Returns True if successful."""
|
|
global _sqlite_initialized, _sqlite_available, _SQLiteConnection
|
|
|
|
if _sqlite_initialized:
|
|
return _sqlite_available
|
|
|
|
_sqlite_initialized = True
|
|
|
|
try:
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
sqlite_dll = Path.Combine(script_dir, 'System.Data.SQLite.dll')
|
|
|
|
if not File.Exists(sqlite_dll):
|
|
print "System.Data.SQLite.dll not found at: " + sqlite_dll
|
|
return False
|
|
|
|
# Set DLL search path to find e_sqlite3.dll (do this once)
|
|
if System.IntPtr.Size == 8:
|
|
native_path = Path.Combine(script_dir, 'x64')
|
|
else:
|
|
native_path = Path.Combine(script_dir, 'x86')
|
|
|
|
current_path = System.Environment.GetEnvironmentVariable("PATH")
|
|
if native_path not in current_path:
|
|
System.Environment.SetEnvironmentVariable("PATH", native_path + ";" + current_path)
|
|
|
|
clr.AddReferenceToFileAndPath(sqlite_dll)
|
|
from System.Data.SQLite import SQLiteConnection
|
|
_SQLiteConnection = SQLiteConnection
|
|
|
|
_sqlite_available = True
|
|
print "SQLite initialized successfully"
|
|
return True
|
|
|
|
except Exception as e:
|
|
print "SQLite initialization error: " + str(e)
|
|
return False
|
|
|
|
# Initialize SQLite at module load
|
|
_init_sqlite()
|
|
|
|
# ============== Settings Dialog ==============
|
|
|
|
class SettingsForm(Form):
|
|
def __init__(self):
|
|
self.InitializeComponent()
|
|
self.LoadSettings()
|
|
|
|
def InitializeComponent(self):
|
|
self.SuspendLayout()
|
|
|
|
# API Key Label
|
|
self._apiKeyLabel = Label()
|
|
self._apiKeyLabel.Text = "ComicVine API Key:"
|
|
self._apiKeyLabel.Location = Point(12, 15)
|
|
self._apiKeyLabel.Size = Size(120, 20)
|
|
|
|
# API Key TextBox
|
|
self._apiKeyTextBox = TextBox()
|
|
self._apiKeyTextBox.Location = Point(140, 12)
|
|
self._apiKeyTextBox.Size = Size(280, 20)
|
|
self._apiKeyTextBox.UseSystemPasswordChar = True
|
|
|
|
# Show/Hide API Key button
|
|
self._showApiKey = Button()
|
|
self._showApiKey.Text = "Show"
|
|
self._showApiKey.Location = Point(425, 10)
|
|
self._showApiKey.Size = Size(50, 24)
|
|
self._showApiKey.Click += self.ToggleApiKeyVisibility
|
|
|
|
# Skip API checkbox
|
|
self._skipApiCheckBox = CheckBox()
|
|
self._skipApiCheckBox.Text = "Skip API if not found in local database (local DB only)"
|
|
self._skipApiCheckBox.Location = Point(12, 50)
|
|
self._skipApiCheckBox.Size = Size(400, 24)
|
|
self._skipApiCheckBox.CheckedChanged += self.OnSkipApiChanged
|
|
|
|
# Always use API checkbox
|
|
self._alwaysApiCheckBox = CheckBox()
|
|
self._alwaysApiCheckBox.Text = "Always use API (skip local database)"
|
|
self._alwaysApiCheckBox.Location = Point(12, 80)
|
|
self._alwaysApiCheckBox.Size = Size(400, 24)
|
|
self._alwaysApiCheckBox.CheckedChanged += self.OnAlwaysApiChanged
|
|
|
|
# API Delay Label
|
|
self._apiDelayLabel = Label()
|
|
self._apiDelayLabel.Text = "API delay (seconds):"
|
|
self._apiDelayLabel.Location = Point(12, 115)
|
|
self._apiDelayLabel.Size = Size(120, 20)
|
|
|
|
# API Delay TextBox
|
|
self._apiDelayTextBox = TextBox()
|
|
self._apiDelayTextBox.Location = Point(140, 112)
|
|
self._apiDelayTextBox.Size = Size(50, 20)
|
|
|
|
# API Delay hint
|
|
self._apiDelayHint = Label()
|
|
self._apiDelayHint.Text = "(0 = no delay)"
|
|
self._apiDelayHint.Location = Point(195, 115)
|
|
self._apiDelayHint.Size = Size(100, 20)
|
|
self._apiDelayHint.ForeColor = Color.Gray
|
|
|
|
# Info label
|
|
self._infoLabel = Label()
|
|
self._infoLabel.Text = "Note: Local database (localcv.db) must be in the plugin folder."
|
|
self._infoLabel.Location = Point(12, 145)
|
|
self._infoLabel.Size = Size(460, 20)
|
|
self._infoLabel.ForeColor = Color.Gray
|
|
|
|
# Save Button
|
|
self._saveButton = Button()
|
|
self._saveButton.Text = "Save"
|
|
self._saveButton.Location = Point(310, 175)
|
|
self._saveButton.Size = Size(80, 28)
|
|
self._saveButton.Click += self.SaveClicked
|
|
|
|
# Cancel Button
|
|
self._cancelButton = Button()
|
|
self._cancelButton.Text = "Cancel"
|
|
self._cancelButton.Location = Point(395, 175)
|
|
self._cancelButton.Size = Size(80, 28)
|
|
self._cancelButton.Click += self.CancelClicked
|
|
|
|
# Form settings
|
|
self.ClientSize = Size(490, 215)
|
|
self.Text = "CVIssueCount Settings"
|
|
self.FormBorderStyle = FormBorderStyle.FixedDialog
|
|
self.MaximizeBox = False
|
|
self.MinimizeBox = False
|
|
self.StartPosition = FormStartPosition.CenterParent
|
|
self.AcceptButton = self._saveButton
|
|
self.CancelButton = self._cancelButton
|
|
|
|
# Add controls
|
|
self.Controls.Add(self._apiKeyLabel)
|
|
self.Controls.Add(self._apiKeyTextBox)
|
|
self.Controls.Add(self._showApiKey)
|
|
self.Controls.Add(self._skipApiCheckBox)
|
|
self.Controls.Add(self._alwaysApiCheckBox)
|
|
self.Controls.Add(self._apiDelayLabel)
|
|
self.Controls.Add(self._apiDelayTextBox)
|
|
self.Controls.Add(self._apiDelayHint)
|
|
self.Controls.Add(self._infoLabel)
|
|
self.Controls.Add(self._saveButton)
|
|
self.Controls.Add(self._cancelButton)
|
|
|
|
self.ResumeLayout(False)
|
|
|
|
def LoadSettings(self):
|
|
self._apiKeyTextBox.Text = settings.api_key
|
|
self._skipApiCheckBox.Checked = settings.skip_api_if_not_in_db
|
|
self._alwaysApiCheckBox.Checked = settings.always_use_api
|
|
self._apiDelayTextBox.Text = str(settings.api_delay)
|
|
|
|
def ToggleApiKeyVisibility(self, sender, e):
|
|
self._apiKeyTextBox.UseSystemPasswordChar = not self._apiKeyTextBox.UseSystemPasswordChar
|
|
self._showApiKey.Text = "Hide" if not self._apiKeyTextBox.UseSystemPasswordChar else "Show"
|
|
|
|
def OnSkipApiChanged(self, sender, e):
|
|
if self._skipApiCheckBox.Checked:
|
|
self._alwaysApiCheckBox.Checked = False
|
|
|
|
def OnAlwaysApiChanged(self, sender, e):
|
|
if self._alwaysApiCheckBox.Checked:
|
|
self._skipApiCheckBox.Checked = False
|
|
|
|
def SaveClicked(self, sender, e):
|
|
settings.api_key = self._apiKeyTextBox.Text
|
|
settings.skip_api_if_not_in_db = self._skipApiCheckBox.Checked
|
|
settings.always_use_api = self._alwaysApiCheckBox.Checked
|
|
try:
|
|
settings.api_delay = int(self._apiDelayTextBox.Text)
|
|
if settings.api_delay < 0:
|
|
settings.api_delay = 0
|
|
except:
|
|
settings.api_delay = 10
|
|
settings.save_to_file()
|
|
self.DialogResult = DialogResult.OK
|
|
self.Close()
|
|
|
|
def CancelClicked(self, sender, e):
|
|
self.DialogResult = DialogResult.Cancel
|
|
self.Close()
|
|
|
|
# ============== Main Entry Points ==============
|
|
|
|
#@Name CVIssueCount
|
|
#@Hook Books
|
|
#@Image CVIssueCount.png
|
|
#@Key CVIssueCount
|
|
def CVIssueCount(books):
|
|
"""Main entry point - called from context menu on Books."""
|
|
if books:
|
|
f = CVIssueCountForm(books)
|
|
r = f.ShowDialog()
|
|
else:
|
|
MessageBox.Show("No books selected")
|
|
return
|
|
|
|
#@Key CVIssueCount
|
|
#@Hook ConfigScript
|
|
def CVIssueCountSettings():
|
|
"""Entry point for ConfigScript hook - shows settings from File menu."""
|
|
f = SettingsForm()
|
|
f.ShowDialog()
|
|
|
|
# ============== Main Form ==============
|
|
|
|
class CVIssueCountForm(Form):
|
|
def __init__(self, books):
|
|
self.InitializeComponent()
|
|
self.books = books
|
|
self.percentage = 1.0/len(books)*100
|
|
self.progresspercent = 0.0
|
|
self.stop = False
|
|
|
|
def InitializeComponent(self):
|
|
self._label1 = System.Windows.Forms.Label()
|
|
self._Okay = System.Windows.Forms.Button()
|
|
self._Cancel = System.Windows.Forms.Button()
|
|
self._Settings = System.Windows.Forms.Button()
|
|
self._progress = System.Windows.Forms.ProgressBar()
|
|
self.worker = BackgroundWorker()
|
|
self.SuspendLayout()
|
|
|
|
self.worker.WorkerSupportsCancellation = True
|
|
self.worker.WorkerReportsProgress = True
|
|
self.worker.DoWork += self.DoWork
|
|
self.worker.ProgressChanged += self.ReportProgress
|
|
self.worker.RunWorkerCompleted += self.WorkerCompleted
|
|
|
|
self._progress.Location = System.Drawing.Point(12, 114)
|
|
self._progress.Size = System.Drawing.Size(456, 17)
|
|
self._progress.TabIndex = 4
|
|
#
|
|
# label1
|
|
#
|
|
self._label1.AutoSize = True
|
|
self._label1.Location = System.Drawing.Point(12, 53)
|
|
self._label1.Name = "label1"
|
|
self._label1.Size = System.Drawing.Size(16, 13)
|
|
self._label1.TabIndex = 3
|
|
self._label1.Text = "Start searching Comicvine for issue counts using the 'Start' button"
|
|
#
|
|
# Settings Button
|
|
#
|
|
self._Settings.Location = System.Drawing.Point(12, 137)
|
|
self._Settings.Name = "Settings"
|
|
self._Settings.Size = System.Drawing.Size(75, 23)
|
|
self._Settings.TabIndex = 7
|
|
self._Settings.Text = "Settings"
|
|
self._Settings.UseVisualStyleBackColor = True
|
|
self._Settings.Click += self.SettingsClicked
|
|
#
|
|
# Okay
|
|
#
|
|
self._Okay.Location = System.Drawing.Point(312, 137)
|
|
self._Okay.Name = "Okay"
|
|
self._Okay.Size = System.Drawing.Size(75, 23)
|
|
self._Okay.TabIndex = 5
|
|
self._Okay.Text = "Start"
|
|
self._Okay.UseVisualStyleBackColor = True
|
|
self._Okay.Click += self.OkayClicked
|
|
#
|
|
# Cancel
|
|
#
|
|
self._Cancel.Location = System.Drawing.Point(393, 137)
|
|
self._Cancel.Name = "Cancel"
|
|
self._Cancel.Size = System.Drawing.Size(75, 23)
|
|
self._Cancel.TabIndex = 6
|
|
self._Cancel.Text = "Cancel"
|
|
self._Cancel.Enabled = False
|
|
self._Cancel.UseVisualStyleBackColor = True
|
|
self._Cancel.Click += self.CancelClicked
|
|
|
|
self.ClientSize = System.Drawing.Size(483, 170)
|
|
self.Controls.Add(self._Settings)
|
|
self.Controls.Add(self._Cancel)
|
|
self.Controls.Add(self._Okay)
|
|
self.Controls.Add(self._progress)
|
|
self.Controls.Add(self._label1)
|
|
self.Name = "CVIssueCount"
|
|
self.Text = "Get issue Count from CV"
|
|
self.MinimizeBox = False
|
|
self.MaximizeBox = False
|
|
self.AcceptButton = self._Okay
|
|
self.FormBorderStyle = FormBorderStyle.FixedDialog
|
|
self.StartPosition = FormStartPosition.CenterParent
|
|
|
|
self.ResumeLayout(False)
|
|
self.PerformLayout()
|
|
self.FormClosing += self.CheckClosing
|
|
|
|
|
|
|
|
def CheckClosing(self, sender, e):
|
|
if self.worker.IsBusy:
|
|
self.worker.CancelAsync()
|
|
e.Cancel = True
|
|
#print "close"
|
|
|
|
def SettingsClicked(self, sender, e):
|
|
f = SettingsForm()
|
|
f.ShowDialog()
|
|
|
|
def OkayClicked(self, sender, e):
|
|
if self._Okay.Text == "Start":
|
|
if self.worker.IsBusy == False:
|
|
self.worker.RunWorkerAsync()
|
|
self._Cancel.Enabled = True
|
|
self._Okay.Enabled = False
|
|
self._Settings.Enabled = False
|
|
#else:
|
|
#self.DialogResult = DialogResult.OK
|
|
|
|
def CancelClicked(self, sender, e):
|
|
if self.worker.IsBusy:
|
|
self.worker.CancelAsync()
|
|
self._Cancel.Enabled = False
|
|
|
|
def DoWork(self, sender, e):
|
|
e.Result = getIssueCount(sender,self.books)
|
|
|
|
def ReportProgress(self, sender, e):
|
|
self.progresspercent = self.percentage*e.ProgressPercentage
|
|
self._progress.Value = int(round(self.progresspercent))
|
|
self._label1.Text = "Searching for " + e.UserState.ToString()
|
|
|
|
|
|
def WorkerCompleted(self, sender, e):
|
|
self._Okay.Text = "Done"
|
|
self.Close()
|
|
self.Dispose()
|
|
|
|
# ============== Database Functions ==============
|
|
|
|
def getIssueCountFromDB(volume_id, db_path):
|
|
"""Try to get issue count from local database. Returns None if not found."""
|
|
if not _sqlite_available:
|
|
return None
|
|
|
|
conn = None
|
|
try:
|
|
conn = _SQLiteConnection("Data Source=" + db_path + ";Version=3;Read Only=True;BusyTimeout=5000;")
|
|
conn.Open()
|
|
cmd = conn.CreateCommand()
|
|
cmd.CommandText = "SELECT count_of_issues FROM cv_volume WHERE id = " + str(int(volume_id))
|
|
result = cmd.ExecuteScalar()
|
|
if result is not None:
|
|
return int(result)
|
|
except Exception as e:
|
|
print "DB lookup error: " + str(e)
|
|
finally:
|
|
if conn is not None:
|
|
try:
|
|
conn.Close()
|
|
except:
|
|
pass
|
|
return None
|
|
|
|
# ============== Main Logic ==============
|
|
|
|
def getIssueCount(worker,books):
|
|
|
|
# Get API key from settings
|
|
API_KEY = settings.api_key if settings.api_key else "<API_KEY>"
|
|
|
|
# Check for local database
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
db_path = os.path.join(script_dir, "localcv.db")
|
|
db_exists = os.path.exists(db_path)
|
|
|
|
# Determine what sources to use based on settings
|
|
use_local_db = db_exists and not settings.always_use_api
|
|
use_api = not settings.skip_api_if_not_in_db
|
|
|
|
if settings.always_use_api:
|
|
print "Settings: Always use API (skipping local DB)"
|
|
elif settings.skip_api_if_not_in_db:
|
|
print "Settings: Skip API if not in local DB"
|
|
if not db_exists:
|
|
print "Warning: Local database not found!"
|
|
elif use_local_db:
|
|
print "Using local database: " + db_path
|
|
else:
|
|
print "Local database not found, using API"
|
|
|
|
all_books_original = ComicRack.App.GetLibraryBooks()
|
|
|
|
# Build a lookup dictionary: volume_id -> list of books (do this ONCE)
|
|
print "Building volume lookup index..."
|
|
volume_to_books = {}
|
|
for book in all_books_original:
|
|
vol = book.GetCustomValue("comicvine_volume")
|
|
if vol:
|
|
if vol not in volume_to_books:
|
|
volume_to_books[vol] = []
|
|
volume_to_books[vol].append(book)
|
|
print "Index built: " + str(len(volume_to_books)) + " volumes"
|
|
|
|
stop=False
|
|
CheckedVolumes=list()
|
|
IssueCountList=list()
|
|
IssueCount=0
|
|
|
|
failed = 0
|
|
count = 0
|
|
report = System.Text.StringBuilder()
|
|
for book in books:
|
|
if worker.CancellationPending:
|
|
return failed,report.ToString()
|
|
|
|
volume = book.GetCustomValue("comicvine_volume")
|
|
seriesVolume = volume
|
|
bookinfo = "#" + str(book.Number) + " " + book.Series + " (" + str(book.Volume) + ")"
|
|
|
|
count += 1
|
|
worker.ReportProgress(count,bookinfo)
|
|
|
|
|
|
now = datetime.now()
|
|
print str(now.strftime("%m/%d/%Y, %H:%M:%S"))
|
|
|
|
if volume not in CheckedVolumes:
|
|
IssueCount = None
|
|
|
|
# Try local database first (unless always_use_api is set)
|
|
if use_local_db:
|
|
IssueCount = getIssueCountFromDB(volume, db_path)
|
|
if IssueCount is not None:
|
|
print str(volume) + "'s count is " + str(IssueCount) + " (from local DB)"
|
|
report.Append(str(IssueCount))
|
|
|
|
# Fall back to API if not found in local DB (unless skip_api_if_not_in_db is set)
|
|
if IssueCount is None and use_api:
|
|
QUERY = "https://comicvine.gamespot.com/api/volume/4050-"+ volume +"/?api_key=" + API_KEY + "&format=xml&field_list=count_of_issues"
|
|
print QUERY
|
|
data = _read_url(QUERY.encode('utf-8'))
|
|
|
|
if settings.api_delay > 0:
|
|
time.sleep(settings.api_delay)
|
|
|
|
doc = System.Xml.XmlDocument()
|
|
doc.LoadXml(data)
|
|
elemList = doc.GetElementsByTagName("count_of_issues")
|
|
|
|
for i in elemList:
|
|
IssueCount = int(i.InnerXml)
|
|
if i.InnerText == "":
|
|
failed += 1
|
|
report.Append(i.InnerText)
|
|
else:
|
|
report.Append(i.InnerText)
|
|
print str(volume) + "'s count is " + str(IssueCount) + " (from API)"
|
|
elif IssueCount is None:
|
|
print str(volume) + " not found in local DB (API skipped per settings)"
|
|
failed += 1
|
|
|
|
CheckedVolumes.append(volume)
|
|
IssueCountList.append(IssueCount if IssueCount else 0)
|
|
|
|
# Update all books with this volume using the pre-built index (fast O(1) lookup)
|
|
if seriesVolume in volume_to_books:
|
|
for b in volume_to_books[seriesVolume]:
|
|
if b.Number.isnumeric:
|
|
b.Count = IssueCount if IssueCount else 0
|
|
b.SetCustomValue("comicvine_issue_count",str(IssueCount if IssueCount else 0))
|
|
|
|
return failed,report.ToString()
|
|
|
|
def _read_url(url):
|
|
|
|
page = ''
|
|
|
|
requestUri = url
|
|
|
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
|
|
|
|
Req = HttpWebRequest.Create(requestUri)
|
|
Req.Timeout = 60000
|
|
Req.UserAgent = "CVIssueCount/" + " (https://gitea.baerentsen.space/FrederikBaerentsen/ComicRack_Scripts/src/branch/master/CVIssueCount)"
|
|
Req.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
|
|
|
|
#Req.Referer = requestUri
|
|
Req.Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
|
|
Req.Headers.Add('Accept-Language','en-US,en;q=0.9,it;q=0.8,fr;q=0.7,de-DE;q=0.6,de;q=0.5')
|
|
|
|
Req.KeepAlive = True
|
|
webresponse = Req.GetResponse()
|
|
|
|
a = webresponse.Cookies
|
|
|
|
inStream = webresponse.GetResponseStream()
|
|
encode = Encoding.GetEncoding("utf-8")
|
|
ReadStream = StreamReader(inStream, encode)
|
|
page = ReadStream.ReadToEnd()
|
|
|
|
|
|
try:
|
|
inStream.Close()
|
|
webresponse.Close()
|
|
except:
|
|
pass
|
|
|
|
return page
|