├── .gitignore ├── composer.json ├── run.php ├── README.md ├── COPYING └── src ├── WikiTable.php └── Slurper.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | .idea -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "addwiki/mediawiki-api": "~0.5.0", 4 | "stichoza/google-translate-php": "~3.1" 5 | }, 6 | "autoload": { 7 | "psr-4": {"GtwlSlurp\\": "src/"} 8 | } 9 | } -------------------------------------------------------------------------------- /run.php: -------------------------------------------------------------------------------- 1 | 'en', 21 | 'highlight' => 20, 22 | ) ); 23 | 24 | echo "Running\n"; 25 | echo $slurper->run(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - - - 2 | German Technical Wish List Vote Slurper 3 | ==================== 4 | 5 | - Votes are only counted if the vote line contains the {{pro}} template (or a redirect to it) as well as a link to a user or user talk page. 6 | - All wish lists are retrieve from Wikipedia:Umfragen/Technische_Wünsche_2015/Alle 7 | - Each wish list MUST then have each wish as a level 4 heading '==== Wish Name ====' 8 | - Each wish MUST then have a vote section ';Unterstützung' 9 | - Each wish list is expected to have a header before the first level 4 heading that is discarded 10 | 11 | ## Usage 12 | 13 | - Clone 14 | - Composer install 15 | - php run.php -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/WikiTable.php: -------------------------------------------------------------------------------- 1 | headings = $headings; 30 | $this->rows = $rows; 31 | $this->config = $config; 32 | } 33 | 34 | public function __toString() { 35 | return $this->getTableStart() . 36 | $this->getTableHeadings() . 37 | $this->getTableRows() . 38 | $this->getTableEnd(); 39 | } 40 | 41 | private function getTableStart() { 42 | $string = '{| class="wikitable" style="text-align: center;"' . "\n"; 43 | if ( array_key_exists( 'title', $this->config ) ) { 44 | $string .= '|+ ' . $this->config['title'] . "\n"; 45 | } 46 | return $string; 47 | } 48 | 49 | private function getTableHeadings() { 50 | $headings = ''; 51 | foreach( $this->headings as $heading ) { 52 | $headings .= '! ' . $heading . "\n"; 53 | } 54 | return $headings; 55 | } 56 | 57 | private function getTableRows() { 58 | $rowsString = ''; 59 | foreach( $this->rows as $values ) { 60 | $rowsString .= "|-\n"; 61 | foreach( $values as $value ) { 62 | $rowsString .= "| $value\n"; 63 | } 64 | } 65 | return $rowsString; 66 | } 67 | 68 | private function getTableEnd() { 69 | return '|}'; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/Slurper.php: -------------------------------------------------------------------------------- 1 | translate = new TranslateClient( 'de', $config['translate'] ); 31 | } 32 | if( array_key_exists( 'highlight', $config ) ) { 33 | $this->highlight = $config['highlight']; 34 | } 35 | 36 | $api = new MediawikiApi( 'https://' . $this->domain . '/w/api.php' ); 37 | $mw = new MediawikiFactory( $api ); 38 | $this->site = $mw; 39 | } 40 | 41 | private function getSubArticle( $subPage ) { 42 | return $this->mainArticle . '/' . $subPage; 43 | } 44 | 45 | public function run() { 46 | $pageTitles = $this->getAllSubPageTitles(); 47 | 48 | $data = array(); 49 | 50 | foreach( $pageTitles as $pageTitle ) { 51 | foreach( $this->getDataForPage( $pageTitle ) as $wish => $wishData ) { 52 | $data[$wish] = $wishData; 53 | } 54 | } 55 | 56 | return $this->output( $data ); 57 | } 58 | 59 | private function output( $result ) { 60 | asort( $result ); 61 | $result = array_reverse( $result, true ); 62 | 63 | $tableRows = array(); 64 | 65 | $total = 0; 66 | $wishCounter = 0; 67 | foreach( $result as $wishName => $data ) { 68 | $wishCounter += 1; 69 | if( $this->translate ) { 70 | $wishName = $this->translate->translate( $wishName ); 71 | } 72 | $link = '[[' . $data['link'] . '|' . $wishName . ']]'; 73 | $voteCount = $data['votes']; 74 | if( $this->highlight >= $wishCounter ) { 75 | $link = "'''" . $link . "'''"; 76 | $voteCount = "'''" . $voteCount . "'''"; 77 | } 78 | $tableRows[] = array( $voteCount, $link ); 79 | $total += $data['votes']; 80 | } 81 | 82 | $table = new WikiTable( 83 | array( "Votes ($total)", 'Wish(' . count( $tableRows ) . ')' ), 84 | $tableRows, 85 | array( 'title' => 'GTWL Votes' ) 86 | ); 87 | 88 | return $table; 89 | } 90 | 91 | private function getDataForPage( $pageTitle ) { 92 | $page = $this->site->newPageGetter()->getFromTitle( $pageTitle ); 93 | $text = $page->getRevisions()->getLatest()->getContent()->getData(); 94 | 95 | preg_match_all( '/====([^(====)]+)====/i', $text, $headings ); 96 | $split = preg_split( '/====[^(====)]+====/i', $text ); 97 | array_shift( $split ); 98 | $headings = $headings[1]; 99 | 100 | if( count( $headings ) !== count( $split ) ){ 101 | echo "Something wrong on $pageTitle\n"; 102 | echo "Got a different number of headings and sections\n"; 103 | die(); 104 | } 105 | 106 | $data = array(); 107 | foreach( $split as $key => $wishSection ) { 108 | $wishName = trim($headings[$key]); 109 | $wishSectionSplit = preg_split( '/\n;Unterstützung/i', $wishSection ); 110 | $voteSection = $wishSectionSplit[1]; 111 | 112 | $data[$wishName]['users'] = array(); 113 | $data[$wishName]['votes'] = 0; 114 | $data[$wishName]['link'] = $pageTitle . '#' . $wishName; 115 | 116 | foreach( explode( "\n", $voteSection ) as $line ) { 117 | if( 118 | // Require the {{pro}} template 119 | preg_match( $this->getProTemplateRegex(), $line ) && 120 | // Require a user / user talk link 121 | preg_match( $this->getUserLinkRegex(), $line, $userMatches ) 122 | ) { 123 | $data[$wishName]['users'][] = $userMatches[2]; 124 | $data[$wishName]['votes'] += 1; 125 | } 126 | } 127 | } 128 | 129 | return $data; 130 | } 131 | 132 | private function getProTemplateRegex() { 133 | $namespaces = array( 'Template', 'Vorlage' ); 134 | $titles = array( 'Pro', 'Dafür' ); 135 | 136 | $nsPart = '((' . implode( '|', $namespaces ) . '):)?'; 137 | $titlePart = '(' . implode( '|', $titles ) . ')'; 138 | 139 | return '/\{\{' . $nsPart . $titlePart . '\}\}/i'; 140 | } 141 | 142 | private function getUserLinkRegex() { 143 | $namespaces = array( 'User', 'Benutzer', 'Benutzerin', 'Benutzer Diskussion', 'Benutzerin Diskussion', 'User Talk' ); 144 | 145 | $nsPart = '(' . implode( '|', $namespaces ) . '):'; 146 | 147 | return '/\[\[' . $nsPart . '([^\]\|]+)' . '(\]\]|\|)/i'; 148 | } 149 | 150 | private function getAllSubPageTitles() { 151 | $allPage = $this->site->newPageGetter()->getFromTitle( $this->getSubArticle( 'Alle' ) ); 152 | $allText = $allPage->getRevisions()->getLatest()->getContent()->getData(); 153 | 154 | preg_match_all( '/\{\{\.\.\/(.+)\}\}/i', $allText, $matches ); 155 | 156 | $pageSubTitles = array(); 157 | foreach( $matches[1] as $match ) { 158 | $pageSubTitles[] = $this->getSubArticle( trim( $match ) ); 159 | } 160 | 161 | return $pageSubTitles; 162 | } 163 | 164 | } 165 | --------------------------------------------------------------------------------