No Description

charts.py 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #
  4. # charts.py
  5. #
  6. # original version by:
  7. #
  8. # (C) Pywikibot team, 2006-2014 as basic.py
  9. #
  10. # Distributed under the terms of the MIT license.
  11. #
  12. # modified by:
  13. #
  14. # Copyright 2017 Jonathan Golder <jonathan@golderweb.de>
  15. #
  16. # This program is free software; you can redistribute it and/or modify
  17. # it under the terms of the GNU General Public License as published by
  18. # the Free Software Foundation; either version 3 of the License, or
  19. # (at your option) any later version.
  20. #
  21. # This program is distributed in the hope that it will be useful,
  22. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. # GNU General Public License for more details.
  25. #
  26. # You should have received a copy of the GNU General Public License
  27. # along with this program; if not, write to the Free Software
  28. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  29. # MA 02110-1301, USA.
  30. #
  31. #
  32. """
  33. Bot which automatically updates a ChartsSummaryPage like
  34. [[Portal:Charts_und_Popmusik/Aktuelle_Nummer-eins-Hits]] by reading linked
  35. CountryLists
  36. The following parameters are supported:
  37. &params;
  38. -always If given, request for confirmation of edit is short circuited
  39. Use for unattended run
  40. -force-reload If given, countrylists will be always parsed regardless if
  41. needed or not
  42. """
  43. import locale
  44. import os
  45. import sys
  46. import pywikibot
  47. from pywikibot import pagegenerators
  48. import jogobot
  49. from summarypage import SummaryPage
  50. # This is required for the text that is shown when you run this script
  51. # with the parameter -help.
  52. docuReplacements = {
  53. '&params;': pagegenerators.parameterHelp
  54. }
  55. class ChartsBot( ):
  56. """
  57. Bot which automatically updates a ChartsSummaryPage like
  58. [[Portal:Charts_und_Popmusik/Aktuelle_Nummer-eins-Hits]] by reading linked
  59. CountryLists
  60. """
  61. def __init__( self, generator, always, force_reload ):
  62. """
  63. Constructor.
  64. @param generator: the page generator that determines on which pages
  65. to work
  66. @type generator: generator
  67. @param always: if True, request for confirmation of edit is short
  68. circuited. Use for unattended run
  69. @type always: bool
  70. @param force-reload: If given, countrylists will be always parsed
  71. regardless if needed or not
  72. @type force-reload: bool
  73. """
  74. self.generator = generator
  75. self.always = always
  76. # Force parsing of countrylist
  77. self.force_reload = force_reload
  78. # Output Information
  79. jogobot.output( "Chartsbot invoked" )
  80. # Save pywikibot site object
  81. self.site = pywikibot.Site()
  82. # Define edit summary
  83. self.summary = jogobot.config["charts"]["edit_summary"].strip()
  84. # Make sure summary starts with "Bot:"
  85. if not self.summary[:len("Bot:")] == "Bot:":
  86. self.summary = "Bot: " + self.summary.strip()
  87. # Set locale to 'de_DE.UTF-8'
  88. locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
  89. def run(self):
  90. """Process each page from the generator."""
  91. # Count skipped pages (redirect or missing)
  92. skipped = 0
  93. for page in self.generator:
  94. if not self.treat(page):
  95. skipped += 1
  96. if skipped:
  97. jogobot.output( "Chartsbot finished, {skipped} page(s) skipped"
  98. .format( skipped=skipped ) )
  99. else:
  100. jogobot.output( "Chartsbot finished successfully" )
  101. def treat(self, page):
  102. """Load the given page, does some changes, and saves it."""
  103. text = self.load(page)
  104. if not text:
  105. return False
  106. ################################################################
  107. # NOTE: Here you can modify the text in whatever way you want. #
  108. ################################################################
  109. # Initialise and treat SummaryPageWorker
  110. sumpage = SummaryPage( text, self.force_reload )
  111. sumpage.treat()
  112. # Check if editing is needed and if so get new text
  113. if sumpage.get_new_text():
  114. text = sumpage.get_new_text()
  115. if not self.save(text, page, self.summary, False):
  116. jogobot.output(u'Page %s not saved.' % page.title(asLink=True))
  117. return True
  118. def load(self, page):
  119. """Load the text of the given page."""
  120. try:
  121. # Load the page
  122. text = page.get()
  123. except pywikibot.NoPage:
  124. jogobot.output( u"Page %s does not exist; skipping."
  125. % page.title(asLink=True), "ERROR" )
  126. except pywikibot.IsRedirectPage:
  127. jogobot.output( u"Page %s is a redirect; skipping."
  128. % page.title(asLink=True), "ERROR" )
  129. else:
  130. return text
  131. return False
  132. def save(self, text, page, comment=None, minorEdit=True,
  133. botflag=True):
  134. """Update the given page with new text."""
  135. # only save if something was changed (and not just revision)
  136. if text != page.get():
  137. # Show diff only in interactive mode or in verbose mode
  138. if not self.always or pywikibot.config.verbose_output:
  139. # Show the title of the page we're working on.
  140. # Highlight the title in purple.
  141. jogobot.output( u">>> \03{lightpurple}%s\03{default} <<<"
  142. % page.title())
  143. # show what was changed
  144. pywikibot.showDiff(page.get(), text)
  145. jogobot.output(u'Comment: %s' % comment)
  146. if self.always or pywikibot.input_yn(
  147. u'Do you want to accept these changes?',
  148. default=False, automatic_quit=False):
  149. try:
  150. page.text = text
  151. # Save the page
  152. page.save(summary=comment or self.comment,
  153. minor=minorEdit, botflag=botflag)
  154. except pywikibot.LockedPage:
  155. jogobot.output( u"Page %s is locked; skipping."
  156. % page.title(asLink=True), "ERROR" )
  157. except pywikibot.EditConflict:
  158. jogobot.output(
  159. u'Skipping %s because of edit conflict'
  160. % (page.title()), "ERROR")
  161. except pywikibot.SpamfilterError as error:
  162. jogobot.output(
  163. u'Cannot change %s because of spam blacklist \
  164. entry %s'
  165. % (page.title(), error.url), "ERROR")
  166. else:
  167. return True
  168. return False
  169. def main(*args):
  170. """
  171. Process command line arguments and invoke bot.
  172. If args is an empty list, sys.argv is used.
  173. @param args: command line arguments
  174. @type args: list of unicode
  175. """
  176. # Process global arguments to determine desired site
  177. local_args = pywikibot.handle_args(args)
  178. # Get the jogobot-task_slug (basename of current file without ending)
  179. task_slug = os.path.basename(__file__)[:-len(".py")]
  180. # Before run, we need to check wether we are currently active or not
  181. try:
  182. # Will throw Exception if disabled/blocked
  183. jogobot.is_active( task_slug )
  184. except jogobot.jogobot.Blocked:
  185. (type, value, traceback) = sys.exc_info()
  186. jogobot.output( "\03{lightpurple} %s (%s)" % (value, type ),
  187. "CRITICAL" )
  188. except jogobot.jogobot.Disabled:
  189. (type, value, traceback) = sys.exc_info()
  190. jogobot.output( "\03{red} %s (%s)" % (value, type ),
  191. "ERROR" )
  192. # Bot/Task is active
  193. else:
  194. # This factory is responsible for processing command line arguments
  195. # that are also used by other scripts and that determine on which pages
  196. # to work on.
  197. genFactory = pagegenerators.GeneratorFactory()
  198. # The generator gives the pages that should be worked upon.
  199. gen = None
  200. # If always is True, bot won't ask for confirmation of edit (automode)
  201. always = False
  202. # If force_reload is True, bot will always parse Countrylist regardless
  203. # if parsing is needed or not
  204. force_reload = False
  205. # Parse command line arguments
  206. for arg in local_args:
  207. if arg.startswith("-always"):
  208. always = True
  209. elif arg.startswith("-force-reload"):
  210. force_reload = True
  211. else:
  212. pass
  213. genFactory.handleArg(arg)
  214. if not gen:
  215. gen = genFactory.getCombinedGenerator()
  216. if gen:
  217. # The preloading generator is responsible for downloading multiple
  218. # pages from the wiki simultaneously.
  219. gen = pagegenerators.PreloadingGenerator(gen)
  220. bot = ChartsBot(gen, always, force_reload)
  221. if bot:
  222. bot.run()
  223. else:
  224. pywikibot.showHelp()
  225. if( __name__ == "__main__" ):
  226. main()