From 3ba1efb5834e09aa2c0b6ef190359823b8c1c3af Mon Sep 17 00:00:00 2001 From: Lanz Date: Fri, 2 Mar 2012 20:07:04 +0100 Subject: [PATCH] initial commit --- .gitignore | 3 + CHANGES.txt | 150 ++ COPYING.txt | 133 + INSTALL.txt | 30 + ajax.php | 1 + announce.php | 1 + api.php | 116 + artist.php | 5 + better.php | 3 + block_04097.html | 0 blog.php | 1 + bookmarks.php | 3 + browse.php | 1 + captcha.php | 1 + captcha/captcha1.png | Bin 0 -> 20303 bytes captcha/captcha2.png | Bin 0 -> 37623 bytes captcha/captcha3.png | Bin 0 -> 10281 bytes captcha/captcha4.png | Bin 0 -> 33512 bytes captcha/captcha5.png | Bin 0 -> 40120 bytes captcha/captcha6.png | Bin 0 -> 29084 bytes captcha/captcha7.png | Bin 0 -> 44764 bytes captcha/captcha8.png | Bin 0 -> 33500 bytes captcha/captcha9.png | Bin 0 -> 42699 bytes chat.php | 2 + cheaters.php | 2 + classes/ajax_start.php | 112 + classes/class_alias.php | 65 + classes/class_artist.php | 19 + classes/class_artists_similar.php | 372 +++ classes/class_cache.php | 325 +++ classes/class_charts.php | 193 ++ classes/class_cookie.php | 48 + classes/class_debug.php | 536 ++++ classes/class_encrypt.php | 34 + classes/class_feed.php | 70 + classes/class_image.php | 58 + classes/class_invite_tree.php | 219 ++ classes/class_irc.php | 194 ++ classes/class_mysql.php | 338 +++ classes/class_paranoia.php | 88 + classes/class_proxies.php | 43 + classes/class_search.php | 169 ++ classes/class_templates.php | 81 + classes/class_text.php | 702 +++++ classes/class_text2.php | 701 +++++ classes/class_text3.php | 661 +++++ classes/class_time.php | 173 ++ classes/class_torrent.php | 307 +++ classes/class_torrent_32bit.php | 298 +++ classes/class_torrent_form.php | 713 ++++++ classes/class_user_rank.php | 107 + classes/class_useragent.php | 151 ++ classes/class_validate.php | 187 ++ classes/class_wiki.php | 86 + classes/class_zip.php | 184 ++ classes/config.template | 188 ++ classes/fonts/ARIBLK.TTF | Bin 0 -> 103992 bytes classes/fonts/COMIC.TTF | Bin 0 -> 63040 bytes classes/fonts/COMICBD.TTF | Bin 0 -> 55892 bytes classes/fonts/GEORGIA.TTF | Bin 0 -> 62804 bytes classes/fonts/GEORGIAB.TTF | Bin 0 -> 60268 bytes classes/fonts/GEORGIAI.TTF | Bin 0 -> 68172 bytes classes/fonts/GEORGIAZ.TTF | Bin 0 -> 69552 bytes classes/fonts/IMPACT.TTF | Bin 0 -> 126056 bytes classes/fonts/MISTRAL.TTF | Bin 0 -> 102060 bytes classes/fonts/README.TXT | 107 + classes/fonts/TREBUC.TTF | Bin 0 -> 57428 bytes classes/fonts/TREBUCBD.TTF | Bin 0 -> 56576 bytes classes/fonts/TREBUCBI.TTF | Bin 0 -> 55828 bytes classes/fonts/TREBUCIT.TTF | Bin 0 -> 62484 bytes classes/fonts/VERDANA.TTF | Bin 0 -> 52720 bytes classes/fonts/VERDANAB.TTF | Bin 0 -> 53816 bytes classes/fonts/VERDANAI.TTF | Bin 0 -> 57012 bytes classes/fonts/VERDANAZ.TTF | Bin 0 -> 59636 bytes classes/permissions_form.php | 262 ++ classes/regex.php | 13 + classes/script_start.php | 2247 +++++++++++++++++ classes/sphinxapi.php | 1702 +++++++++++++ collage.php | 4 + collages.php | 3 + comments.php | 3 + delays.php | 3 + design/privatefooter.php | 60 + design/privateheader.php | 470 ++++ design/publicfooter.php | 8 + design/publicheader.php | 48 + donate.php | 1 + error.php | 1 + favicon.ico | Bin 0 -> 1406 bytes feeds.php | 91 + flush.php | 18 + forums.php | 3 + friends.php | 3 + gazelle.sql | 1582 ++++++++++++ image.php | 232 ++ inbox.php | 1 + index.php | 1 + irc.php | 3 + irc_raw.php | 39 + log.php | 3 + login.php | 1 + logout.php | 3 + opensearch.php | 73 + peerupdate.php | 6 + register.php | 1 + reports.php | 1 + reportsv2.php | 1 + requests.php | 1 + robots.txt | 10 + rules.php | 1 + schedule.php | 6 + scrape.php | 1 + sections/ajax/announcements.php | 89 + sections/ajax/artist.php | 388 +++ sections/ajax/better/index.php | 38 + sections/ajax/better/single.php | 47 + sections/ajax/better/transcode.php | 111 + sections/ajax/bookmarks.php | 246 ++ sections/ajax/bookmarks/artists.php | 60 + sections/ajax/bookmarks/index.php | 35 + sections/ajax/bookmarks/torrents.php | 246 ++ sections/ajax/browse.php | 597 +++++ sections/ajax/forum/forum.php | 157 ++ sections/ajax/forum/index.php | 107 + sections/ajax/forum/main.php | 93 + sections/ajax/forum/thread.php | 262 ++ sections/ajax/giveback_report.php | 15 + sections/ajax/grab_report.php | 16 + sections/ajax/inbox/inbox.php | 112 + sections/ajax/inbox/index.php | 14 + sections/ajax/inbox/viewconv.php | 92 + sections/ajax/index.php | 88 + sections/ajax/info.php | 37 + sections/ajax/loadavg.php | 15 + sections/ajax/notifications.php | 144 ++ sections/ajax/preview.php | 13 + sections/ajax/request.php | 256 ++ sections/ajax/requests.php | 383 +++ sections/ajax/stats.php | 7 + sections/ajax/subscriptions.php | 122 + sections/ajax/top10/index.php | 29 + sections/ajax/top10/tags.php | 106 + sections/ajax/top10/torrents.php | 194 ++ sections/ajax/top10/users.php | 114 + sections/ajax/torrentgroup.php | 72 + sections/ajax/upload.php | 40 + sections/ajax/user.php | 293 +++ sections/ajax/usersearch.php | 60 + sections/api/access_state.php | 12 + sections/api/index.php | 65 + sections/artist/add_alias.php | 47 + sections/artist/add_similar.php | 51 + sections/artist/artist.php | 815 ++++++ sections/artist/artist_rearrange.php | 690 +++++ sections/artist/autocomplete.php | 54 + sections/artist/delete.php | 84 + sections/artist/delete_alias.php | 37 + sections/artist/delete_similar.php | 23 + sections/artist/download.php | 206 ++ sections/artist/edit.php | 110 + sections/artist/history.php | 36 + sections/artist/index.php | 99 + sections/artist/notify.php | 31 + sections/artist/notifyremove.php | 27 + sections/artist/rename.php | 147 ++ sections/artist/takeedit.php | 58 + sections/artist/vote_similar.php | 28 + sections/better/better.php | 101 + sections/better/files.php | 88 + sections/better/folders.php | 89 + sections/better/index.php | 38 + sections/better/single.php | 63 + sections/better/snatch.php | 120 + sections/better/tags.php | 88 + sections/better/transcode.php | 148 ++ sections/better/upload.php | 107 + sections/blog/index.php | 154 ++ sections/bookmarks/add.php | 64 + sections/bookmarks/artists.php | 95 + sections/bookmarks/functions.php | 44 + sections/bookmarks/index.php | 53 + sections/bookmarks/remove.php | 23 + sections/bookmarks/torrents.php | 423 ++++ sections/captcha/index.php | 50 + sections/chat/index.php | 121 + sections/collages/add_comment.php | 20 + sections/collages/add_torrent.php | 115 + sections/collages/all_comments.php | 131 + sections/collages/browse.php | 308 +++ sections/collages/collage.php | 648 +++++ sections/collages/delete.php | 36 + sections/collages/delete_comment.php | 25 + sections/collages/download.php | 196 ++ sections/collages/edit.php | 77 + sections/collages/edit_handle.php | 50 + sections/collages/get_post.php | 27 + sections/collages/index.php | 93 + sections/collages/manage.php | 90 + sections/collages/manage_handle.php | 29 + sections/collages/new.php | 89 + sections/collages/new_handle.php | 83 + sections/collages/recover.php | 39 + sections/collages/take_delete.php | 41 + sections/collages/takeedit_comment.php | 49 + sections/comments/index.php | 181 ++ sections/donate/cancel.php | 11 + sections/donate/complete.php | 11 + sections/donate/donate.php | 103 + sections/donate/donate_gpal.php | 104 + sections/donate/index.php | 21 + sections/donate/ipn.php | 110 + sections/error/403.php | 5 + sections/error/404.php | 6 + sections/error/413.php | 3 + sections/error/504.php | 3 + sections/error/index.php | 59 + sections/feeds/index.php | 171 ++ sections/forums/add_poll_option.php | 30 + sections/forums/ajax_get_edit.php | 77 + sections/forums/catchup.php | 21 + sections/forums/change_vote.php | 22 + sections/forums/delete.php | 96 + sections/forums/delete_poll_option.php | 35 + sections/forums/edit_rules.php | 72 + sections/forums/forum.php | 236 ++ sections/forums/functions.php | 57 + sections/forums/get_post.php | 38 + sections/forums/index.php | 169 ++ sections/forums/main.php | 111 + sections/forums/mod_thread.php | 257 ++ sections/forums/newthread.php | 149 ++ sections/forums/poll_mod.php | 45 + sections/forums/poll_vote.php | 145 ++ sections/forums/search.php | 304 +++ sections/forums/sticky_post.php | 23 + sections/forums/take_new_thread.php | 191 ++ sections/forums/take_reply.php | 229 ++ sections/forums/takeedit.php | 99 + sections/forums/thread.php | 588 +++++ sections/friends/add.php | 6 + sections/friends/comment.php | 4 + sections/friends/friends.php | 133 + sections/friends/index.php | 33 + sections/friends/remove.php | 4 + sections/image/badprotocol.gif | Bin 0 -> 904 bytes sections/image/forbidden.gif | Bin 0 -> 728 bytes sections/image/index.php | 91 + sections/image/invalid.gif | Bin 0 -> 843 bytes sections/image/invisible.gif | Bin 0 -> 1140 bytes sections/image/nogd.gif | Bin 0 -> 945 bytes sections/image/small.gif | Bin 0 -> 1167 bytes sections/image/timeout.gif | Bin 0 -> 1099 bytes sections/inbox/compose.php | 46 + sections/inbox/conversation.php | 172 ++ sections/inbox/forward.php | 26 + sections/inbox/get_post.php | 35 + sections/inbox/inbox.php | 169 ++ sections/inbox/index.php | 42 + sections/inbox/massdelete_handle.php | 45 + sections/inbox/takecompose.php | 54 + sections/inbox/takeedit.php | 34 + sections/index/index.php | 17 + sections/index/private.php | 478 ++++ sections/index/public.php | 4 + sections/irc/index.php | 0 sections/log/index.php | 231 ++ sections/login/disabled.php | 61 + sections/login/index.php | 322 +++ sections/login/login.php | 65 + sections/login/recover_step1.php | 31 + sections/login/recover_step2.php | 37 + sections/logout/index.php | 4 + sections/peerupdate/index.php | 93 + sections/register/closed.php | 9 + sections/register/code.php | 20 + sections/register/index.php | 212 ++ sections/register/step1.php | 65 + sections/register/step2.php | 10 + sections/reports/array.php | 99 + sections/reports/index.php | 23 + sections/reports/report.php | 290 +++ sections/reports/reports.php | 223 ++ sections/reports/stats.php | 109 + sections/reports/takereport.php | 92 + sections/reports/takeresolve.php | 58 + sections/reportsv2/ajax_change_resolve.php | 42 + sections/reportsv2/ajax_create_report.php | 78 + sections/reportsv2/ajax_grab_report.php | 20 + sections/reportsv2/ajax_new_report.php | 444 ++++ sections/reportsv2/ajax_report.php | 91 + sections/reportsv2/ajax_take_pm.php | 74 + sections/reportsv2/ajax_update_comment.php | 24 + sections/reportsv2/ajax_update_resolve.php | 43 + sections/reportsv2/array.php | 822 ++++++ sections/reportsv2/header.php | 13 + sections/reportsv2/index.php | 66 + sections/reportsv2/report.php | 86 + sections/reportsv2/reports.php | 40 + sections/reportsv2/search.php | 17 + sections/reportsv2/static.php | 651 +++++ sections/reportsv2/takereport.php | 130 + sections/reportsv2/takeresolve.php | 292 +++ sections/reportsv2/views.php | 248 ++ sections/requests/functions.php | 80 + sections/requests/index.php | 190 ++ sections/requests/interim.php | 46 + sections/requests/new_edit.php | 387 +++ sections/requests/request.php | 562 +++++ sections/requests/requests.php | 575 +++++ sections/requests/requests.php.presphinx | 495 ++++ sections/requests/takedelete.php | 62 + sections/requests/takefill.php | 215 ++ sections/requests/takenew_edit.php | 539 ++++ sections/requests/takeunfill.php | 84 + sections/requests/takevote.php | 71 + sections/rules/chat.php | 138 + sections/rules/clients.php | 56 + sections/rules/collages.php | 57 + sections/rules/index.php | 32 + sections/rules/jump.php | 110 + sections/rules/ratio.php | 148 ++ sections/rules/requests.php | 30 + sections/rules/rules.php | 65 + sections/rules/tag.php | 29 + sections/rules/upload.php | 691 +++++ sections/schedule/index.php | 1028 ++++++++ sections/staff/functions.php | 88 + sections/staff/index.php | 128 + sections/staffblog/index.php | 134 + sections/staffpm/ajax_delete_response.php | 29 + sections/staffpm/ajax_edit_response.php | 48 + sections/staffpm/ajax_get_response.php | 36 + sections/staffpm/ajax_preview_response.php | 10 + sections/staffpm/assign.php | 72 + sections/staffpm/common_responses.php | 99 + sections/staffpm/functions.php | 25 + sections/staffpm/index.php | 69 + sections/staffpm/makedonor.php | 43 + sections/staffpm/multiresolve.php | 1 + sections/staffpm/resolve.php | 22 + sections/staffpm/staff_inbox.php | 199 ++ sections/staffpm/takepost.php | 73 + sections/staffpm/unresolve.php | 27 + sections/staffpm/user_inbox.php | 118 + sections/staffpm/viewconv.php | 227 ++ sections/stats/index.php | 15 + sections/stats/torrents.php | 70 + sections/stats/users.php | 162 ++ sections/tools/data/bitcoin_balance.php | 40 + sections/tools/data/browser_support.php | 20 + sections/tools/data/database_specifics.php | 140 + sections/tools/data/donation_log.php | 105 + sections/tools/data/economic_stats.php | 120 + sections/tools/data/invite_pool.php | 105 + sections/tools/data/opcode_stats.php | 145 ++ sections/tools/data/registration_log.php | 95 + sections/tools/data/service_stats.php | 279 ++ sections/tools/data/special_users.php | 38 + sections/tools/data/torrent_stats.php | 72 + sections/tools/data/upscale_pool.php | 82 + sections/tools/data/user_flow.php | 146 ++ sections/tools/index.php | 368 +++ sections/tools/managers/bans.php | 158 ++ sections/tools/managers/dnu_alter.php | 35 + sections/tools/managers/dnu_list.php | 65 + sections/tools/managers/eb.php | 65 + sections/tools/managers/eb_alter.php | 35 + sections/tools/managers/forum_alter.php | 58 + sections/tools/managers/forum_list.php | 168 ++ sections/tools/managers/login_watch.php | 87 + sections/tools/managers/news.php | 67 + sections/tools/managers/ocelot.php | 22 + sections/tools/managers/official_tags.php | 1 + sections/tools/managers/permissions_alter.php | 51 + sections/tools/managers/permissions_list.php | 45 + sections/tools/managers/recommend_add.php | 38 + sections/tools/managers/recommend_alter.php | 25 + sections/tools/managers/recommend_list.php | 61 + sections/tools/managers/tokens.php | 80 + sections/tools/managers/whitelist_alter.php | 52 + sections/tools/managers/whitelist_list.php | 61 + sections/tools/misc/analysis.php | 21 + sections/tools/misc/bugs.php | 0 sections/tools/misc/clear_cache.php | 47 + sections/tools/misc/cli_sandbox.php | 0 sections/tools/misc/create_user.php | 107 + sections/tools/misc/dupe_ip.php | 64 + sections/tools/misc/manipulate_tree.php | 139 + sections/tools/misc/mod_sandbox.php | 0 sections/tools/misc/public_sandbox.php | 0 sections/tools/misc/sandbox1.php | 0 sections/tools/misc/sandbox2.php | 0 sections/tools/misc/sandbox3.php | 0 sections/tools/misc/sandbox4.php | 0 sections/tools/misc/sandbox5.php | 0 sections/tools/misc/sandbox6.php | 0 sections/tools/misc/sandbox7.php | 0 sections/tools/misc/sandbox8.php | 0 sections/tools/misc/update_geoip.php | 122 + sections/tools/services/get_cc.php | 16 + sections/tools/services/get_host.php | 39 + sections/tools/tools.php | 98 + sections/top10/history.php | 183 ++ sections/top10/index.php | 34 + sections/top10/tags.php | 148 ++ sections/top10/torrents.php | 374 +++ sections/top10/users.php | 154 ++ sections/torrents/add_alias.php | 74 + sections/torrents/add_tag.php | 46 + sections/torrents/browse.php | 1046 ++++++++ sections/torrents/browse2.php | 968 +++++++ sections/torrents/delete.php | 279 ++ sections/torrents/delete_alias.php | 58 + sections/torrents/delete_tag.php | 36 + sections/torrents/details.php | 871 +++++++ sections/torrents/download.php | 209 ++ sections/torrents/downloadlist.php | 84 + sections/torrents/edit.php | 160 ++ sections/torrents/editgroup.php | 168 ++ sections/torrents/editgroupid.php | 95 + sections/torrents/functions.php | 165 ++ sections/torrents/grouplog.php | 61 + sections/torrents/history.php | 41 + sections/torrents/index.php | 428 ++++ sections/torrents/manage_artists.php | 56 + sections/torrents/masspm.php | 72 + sections/torrents/merge.php | 97 + sections/torrents/nonwikiedit.php | 68 + sections/torrents/notify.php | 206 ++ sections/torrents/peerlist.php | 69 + sections/torrents/redownload.php | 104 + sections/torrents/rename.php | 32 + sections/torrents/reseed.php | 68 + sections/torrents/snatchlist.php | 68 + sections/torrents/takedelete.php | 51 + sections/torrents/takeedit.php | 412 +++ sections/torrents/takegroupedit.php | 154 ++ sections/torrents/takemasspm.php | 58 + sections/torrents/takenewgroup.php | 69 + sections/torrents/user.php | 465 ++++ sections/torrents/vote_tag.php | 26 + sections/upload/index.php | 14 + sections/upload/upload.php | 157 ++ sections/upload/upload_handle.php | 950 +++++++ sections/user/advancedsearch.php | 726 ++++++ sections/user/connchecker.php | 70 + sections/user/deleteinvite.php | 23 + sections/user/edit.php | 443 ++++ sections/user/index.php | 83 + sections/user/invite.php | 218 ++ sections/user/invitetree.php | 31 + sections/user/linkedfunctions.php | 215 ++ sections/user/manage_linked.php | 1 + sections/user/notify_edit.php | 151 ++ sections/user/notify_handle.php | 157 ++ sections/user/permissions.php | 90 + sections/user/search.php | 91 + sections/user/sessions.php | 91 + sections/user/takeedit.php | 300 +++ sections/user/takeinvite.php | 89 + sections/user/takemoderate.php | 697 +++++ sections/user/user.php | 1251 +++++++++ sections/userhistory/catchup.php | 18 + sections/userhistory/catchup_collages.php | 13 + sections/userhistory/collage_subscribe.php | 23 + sections/userhistory/email_history.php | 116 + sections/userhistory/email_history2.php | 321 +++ sections/userhistory/index.php | 115 + sections/userhistory/ip_history.php | 151 ++ sections/userhistory/ip_tracker_history.php | 79 + sections/userhistory/passkey_history.php | 52 + sections/userhistory/password_history.php | 46 + sections/userhistory/post_history.php | 337 +++ sections/userhistory/subscribed_collages.php | 307 +++ sections/userhistory/subscriptions.php | 188 ++ sections/userhistory/thread_subscribe.php | 34 + sections/userhistory/token_history.php | 116 + sections/wiki/add_alias.php | 19 + sections/wiki/aliases.php | 58 + sections/wiki/article.php | 131 + sections/wiki/compare.php | 94 + sections/wiki/create.php | 34 + sections/wiki/delete.php | 24 + sections/wiki/delete_alias.php | 6 + sections/wiki/edit.php | 38 + sections/wiki/index.php | 88 + sections/wiki/link.php | 18 + sections/wiki/revert.php | 0 sections/wiki/revisions.php | 63 + sections/wiki/search.php | 128 + sections/wiki/splash.php | 43 + sections/wiki/takecreate.php | 60 + sections/wiki/takeedit.php | 50 + sections/wiki/takelink.php | 20 + sections/wiki/wiki_browse.php | 85 + signup.php | 1 + sphinx.conf | 403 +++ staff.php | 2 + staffblog.php | 3 + staffpm.php | 2 + static/blank.gif | Bin 0 -> 42 bytes static/common/avatars/blank.gif | Bin 0 -> 43 bytes static/common/avatars/default.png | Bin 0 -> 15841 bytes static/common/caticons/apps.png | Bin 0 -> 660 bytes static/common/caticons/audiobook.png | Bin 0 -> 826 bytes static/common/caticons/comedy.png | Bin 0 -> 628 bytes static/common/caticons/comics.png | Bin 0 -> 372 bytes static/common/caticons/ebook.png | Bin 0 -> 861 bytes static/common/caticons/elearning.png | Bin 0 -> 733 bytes static/common/caticons/music.png | Bin 0 -> 472 bytes static/common/logo.png | Bin 0 -> 36312 bytes static/common/noartwork/apps.png | Bin 0 -> 10214 bytes static/common/noartwork/audiobook.png | Bin 0 -> 12809 bytes static/common/noartwork/comedy.png | Bin 0 -> 9629 bytes static/common/noartwork/comics.png | Bin 0 -> 8653 bytes static/common/noartwork/ebook.png | Bin 0 -> 10568 bytes static/common/noartwork/elearning.png | Bin 0 -> 15217 bytes static/common/noartwork/music.png | Bin 0 -> 13832 bytes static/common/oink.png | Bin 0 -> 6323 bytes static/common/perfect.gif | Bin 0 -> 15016 bytes static/common/smileys/angry.gif | Bin 0 -> 681 bytes static/common/smileys/biggrin.gif | Bin 0 -> 666 bytes static/common/smileys/blank.gif | Bin 0 -> 681 bytes static/common/smileys/blush.gif | Bin 0 -> 680 bytes static/common/smileys/cool.gif | Bin 0 -> 664 bytes static/common/smileys/creepy.gif | Bin 0 -> 676 bytes static/common/smileys/crying.gif | Bin 0 -> 683 bytes static/common/smileys/eyesright.gif | Bin 0 -> 683 bytes static/common/smileys/frown.gif | Bin 0 -> 679 bytes static/common/smileys/heart.gif | Bin 0 -> 144 bytes static/common/smileys/hmm.gif | Bin 0 -> 685 bytes static/common/smileys/ilu.gif | Bin 0 -> 844 bytes static/common/smileys/laughing.gif | Bin 0 -> 654 bytes static/common/smileys/loveflac.gif | Bin 0 -> 825 bytes static/common/smileys/ninja.gif | Bin 0 -> 725 bytes static/common/smileys/no.gif | Bin 0 -> 1156 bytes static/common/smileys/nod.gif | Bin 0 -> 952 bytes static/common/smileys/ohnoes.gif | Bin 0 -> 667 bytes static/common/smileys/ohshit.gif | Bin 0 -> 670 bytes static/common/smileys/omg.gif | Bin 0 -> 637 bytes static/common/smileys/paddle.gif | Bin 0 -> 768 bytes static/common/smileys/sad.gif | Bin 0 -> 679 bytes static/common/smileys/shifty.gif | Bin 0 -> 892 bytes static/common/smileys/sick.gif | Bin 0 -> 672 bytes static/common/smileys/smile.gif | Bin 0 -> 678 bytes static/common/smileys/sorry.gif | Bin 0 -> 834 bytes static/common/smileys/thanks.gif | Bin 0 -> 820 bytes static/common/smileys/tongue.gif | Bin 0 -> 677 bytes static/common/smileys/wave.gif | Bin 0 -> 1353 bytes static/common/smileys/wink.gif | Bin 0 -> 678 bytes static/common/smileys/worried.gif | Bin 0 -> 679 bytes static/common/smileys/wtf.gif | Bin 0 -> 677 bytes static/common/smileys/wub.gif | Bin 0 -> 726 bytes static/common/symbols/disabled.png | Bin 0 -> 243 bytes static/common/symbols/donor.png | Bin 0 -> 235 bytes static/common/symbols/first-line-support.png | Bin 0 -> 400 bytes static/common/symbols/read.png | Bin 0 -> 147 bytes static/common/symbols/readlocked.png | Bin 0 -> 459 bytes static/common/symbols/readlockedsticky.png | Bin 0 -> 699 bytes static/common/symbols/readsticky.png | Bin 0 -> 522 bytes static/common/symbols/rss.png | Bin 0 -> 890 bytes static/common/symbols/unread.png | Bin 0 -> 406 bytes static/common/symbols/unreadlocked.png | Bin 0 -> 1104 bytes static/common/symbols/unreadlockedsticky.png | Bin 0 -> 973 bytes static/common/symbols/unreadsticky.png | Bin 0 -> 651 bytes static/common/symbols/uploader.png | Bin 0 -> 354 bytes static/common/symbols/warned.png | Bin 0 -> 329 bytes static/common/symbols/watched.png | Bin 0 -> 633 bytes static/common/trumpchart.png | Bin 0 -> 78200 bytes static/functions/artists.js | 369 +++ static/functions/autocomplete.js | 151 ++ static/functions/bbcode.js | 11 + static/functions/browse.js | 188 ++ static/functions/captcha.js | 4 + static/functions/class_ajax.js | 144 ++ static/functions/class_cookie.js | 23 + static/functions/class_countdown.js | 39 + static/functions/class_hotkey.js | 0 static/functions/class_storage.js | 70 + static/functions/collage.js | 132 + static/functions/comments.js | 213 ++ static/functions/delays.js | 60 + static/functions/global.js | 94 + static/functions/inbox.js | 16 + static/functions/iphone.js | 187 ++ static/functions/jquery.js | 18 + static/functions/notifications.js | 29 + static/functions/reportsv2.js | 251 ++ static/functions/requests.js | 186 ++ static/functions/rippy.js | 15 + static/functions/script_start.js | 284 +++ static/functions/sizzle.js | 7 + static/functions/staffpm.js | 112 + static/functions/subscriptions.js | 25 + static/functions/torrent.js | 254 ++ static/functions/transitions.js | 98 + static/functions/upload.js | 281 +++ static/functions/user.js | 137 + static/functions/validate.js | 106 + static/functions/wiki.js | 5 + static/irc/IRCApplet.class | Bin 0 -> 3585 bytes static/irc/english.lng | 93 + static/irc/irc.jar | Bin 0 -> 149769 bytes static/irc/sbox-english.lng | 75 + static/irc/sbox.jar | Bin 0 -> 74977 bytes static/styles/anorex/images/apps.png | Bin 0 -> 660 bytes static/styles/anorex/images/audiobook.png | Bin 0 -> 826 bytes static/styles/anorex/images/bar.gif | Bin 0 -> 54 bytes static/styles/anorex/images/bar_left.gif | Bin 0 -> 54 bytes static/styles/anorex/images/bar_right.gif | Bin 0 -> 54 bytes static/styles/anorex/images/comedy.png | Bin 0 -> 628 bytes static/styles/anorex/images/comics.png | Bin 0 -> 372 bytes static/styles/anorex/images/ebook.png | Bin 0 -> 861 bytes static/styles/anorex/images/elearning.png | Bin 0 -> 733 bytes static/styles/anorex/images/go_last_read.png | Bin 0 -> 273 bytes static/styles/anorex/images/hide.png | Bin 0 -> 556 bytes static/styles/anorex/images/leechers.png | Bin 0 -> 210 bytes static/styles/anorex/images/locked_read.png | Bin 0 -> 3191 bytes .../anorex/images/locked_sticky_read.png | Bin 0 -> 3448 bytes .../anorex/images/locked_sticky_unread.png | Bin 0 -> 3717 bytes static/styles/anorex/images/locked_unread.png | Bin 0 -> 3807 bytes static/styles/anorex/images/logo.png | Bin 0 -> 18525 bytes static/styles/anorex/images/music.png | Bin 0 -> 472 bytes static/styles/anorex/images/read.png | Bin 0 -> 2884 bytes static/styles/anorex/images/seeders.png | Bin 0 -> 204 bytes static/styles/anorex/images/show.png | Bin 0 -> 543 bytes static/styles/anorex/images/snatched.png | Bin 0 -> 281 bytes static/styles/anorex/images/sticky_read.png | Bin 0 -> 3276 bytes static/styles/anorex/images/sticky_unread.png | Bin 0 -> 3388 bytes static/styles/anorex/images/unread.png | Bin 0 -> 3128 bytes static/styles/anorex/images/woodbg.png | Bin 0 -> 3424 bytes static/styles/anorex/images/woodfoot.png | Bin 0 -> 4082 bytes static/styles/anorex/images/woodhead.png | Bin 0 -> 5941 bytes static/styles/anorex/images/woodnav.png | Bin 0 -> 16487 bytes static/styles/anorex/images/woodnavcenter.png | Bin 0 -> 3488 bytes static/styles/anorex/style.css | 798 ++++++ static/styles/arrow.png | Bin 0 -> 259 bytes static/styles/celebrate/banner.gif | Bin 0 -> 9811 bytes static/styles/celebrate/celebrate.css | 7 + static/styles/celebrate/celebratetheme.css | 1036 ++++++++ static/styles/celebrate/fireworks.jpg | Bin 0 -> 687393 bytes static/styles/celebrate/images/Akzidenz.otf | Bin 0 -> 31440 bytes static/styles/celebrate/images/Anonymous.ttf | 3 + static/styles/celebrate/images/Avant.otf | Bin 0 -> 32760 bytes .../styles/celebrate/images/CorpidOffice.ttf | Bin 0 -> 101416 bytes static/styles/celebrate/images/Officina.otf | Bin 0 -> 35440 bytes .../styles/celebrate/images/alert-overlay.png | Bin 0 -> 135 bytes static/styles/celebrate/images/bg_footer.png | Bin 0 -> 2944 bytes static/styles/celebrate/images/bg_header.png | Bin 0 -> 145 bytes static/styles/celebrate/images/bg_inputs.png | Bin 0 -> 284 bytes static/styles/celebrate/images/bg_menu.png | Bin 0 -> 3082 bytes static/styles/celebrate/images/body.jpg | Bin 0 -> 7313 bytes static/styles/celebrate/images/content.png | Bin 0 -> 2804 bytes .../styles/celebrate/images/content_light.png | Bin 0 -> 192 bytes static/styles/celebrate/images/external.png | Bin 0 -> 178 bytes static/styles/celebrate/images/gazelle.png | Bin 0 -> 4256 bytes .../styles/celebrate/images/go_last_read.png | Bin 0 -> 3209 bytes static/styles/celebrate/images/hide.png | Bin 0 -> 122 bytes static/styles/celebrate/images/leechers.png | Bin 0 -> 210 bytes static/styles/celebrate/images/load.gif | Bin 0 -> 723 bytes .../styles/celebrate/images/locked_read.png | Bin 0 -> 596 bytes .../celebrate/images/locked_sticky_read.png | Bin 0 -> 546 bytes .../celebrate/images/locked_sticky_unread.png | Bin 0 -> 3228 bytes .../styles/celebrate/images/locked_unread.png | Bin 0 -> 608 bytes static/styles/celebrate/images/logo.png | Bin 0 -> 1457 bytes static/styles/celebrate/images/nav_matrix.png | Bin 0 -> 8988 bytes .../celebrate/images/nav_matrix_extended.png | Bin 0 -> 19434 bytes .../styles/celebrate/images/nu_nav_matrix.png | Bin 0 -> 38402 bytes static/styles/celebrate/images/poll_left.png | Bin 0 -> 3087 bytes .../styles/celebrate/images/poll_middle.png | Bin 0 -> 2850 bytes static/styles/celebrate/images/poll_right.png | Bin 0 -> 3166 bytes static/styles/celebrate/images/read.png | Bin 0 -> 696 bytes static/styles/celebrate/images/seeders.png | Bin 0 -> 204 bytes static/styles/celebrate/images/show.png | Bin 0 -> 127 bytes static/styles/celebrate/images/snatched.png | Bin 0 -> 281 bytes .../styles/celebrate/images/sticky_read.png | Bin 0 -> 400 bytes .../styles/celebrate/images/sticky_unread.png | Bin 0 -> 3072 bytes .../styles/celebrate/images/table_header.png | Bin 0 -> 462 bytes .../celebrate/images/table_header_dark.png | Bin 0 -> 356 bytes static/styles/celebrate/images/unread.png | Bin 0 -> 3301 bytes static/styles/celebrate/images/wood.jpg | Bin 0 -> 514011 bytes static/styles/celebrate/images/woodlogo.png | Bin 0 -> 4216 bytes static/styles/celebrate/images/wrapper.png | Bin 0 -> 761603 bytes static/styles/dark_ambient/images/apps.png | Bin 0 -> 660 bytes .../styles/dark_ambient/images/audiobook.png | Bin 0 -> 826 bytes static/styles/dark_ambient/images/bar2.png | Bin 0 -> 153 bytes static/styles/dark_ambient/images/bar2_hl.png | Bin 0 -> 148 bytes static/styles/dark_ambient/images/button.png | Bin 0 -> 2817 bytes static/styles/dark_ambient/images/comedy.png | Bin 0 -> 628 bytes static/styles/dark_ambient/images/comics.png | Bin 0 -> 372 bytes .../dark_ambient/images/content_main_x.png | Bin 0 -> 122 bytes .../dark_ambient/images/content_repeat-x.png | Bin 0 -> 155 bytes static/styles/dark_ambient/images/ebook.png | Bin 0 -> 861 bytes .../styles/dark_ambient/images/elearning.png | Bin 0 -> 733 bytes static/styles/dark_ambient/images/filter.png | Bin 0 -> 32999 bytes static/styles/dark_ambient/images/footer.png | Bin 0 -> 137 bytes .../styles/dark_ambient/images/forum_post.png | Bin 0 -> 163 bytes .../dark_ambient/images/go_last_read.png | Bin 0 -> 277 bytes static/styles/dark_ambient/images/header.png | Bin 0 -> 92272 bytes .../dark_ambient/images/header_logo.png | Bin 0 -> 8920 bytes static/styles/dark_ambient/images/hide.png | Bin 0 -> 420 bytes .../styles/dark_ambient/images/icons/60s.jpg | Bin 0 -> 8882 bytes .../styles/dark_ambient/images/icons/70s.jpg | Bin 0 -> 8426 bytes .../styles/dark_ambient/images/icons/80s.jpg | Bin 0 -> 8771 bytes .../styles/dark_ambient/images/icons/90s.jpg | Bin 0 -> 8630 bytes .../dark_ambient/images/icons/Thumbs.db | Bin 0 -> 5632 bytes .../styles/dark_ambient/images/icons/alt.jpg | Bin 0 -> 8570 bytes .../dark_ambient/images/icons/ambient.jpg | Bin 0 -> 8789 bytes .../dark_ambient/images/icons/appsmac.jpg | Bin 0 -> 8759 bytes .../dark_ambient/images/icons/appssnd.jpg | Bin 0 -> 8937 bytes .../dark_ambient/images/icons/appswin.jpg | Bin 0 -> 8360 bytes .../dark_ambient/images/icons/audiobooks.jpg | Bin 0 -> 8607 bytes .../dark_ambient/images/icons/bluegrass.jpg | Bin 0 -> 8906 bytes .../dark_ambient/images/icons/blues.jpg | Bin 0 -> 8831 bytes .../dark_ambient/images/icons/breaks.jpg | Bin 0 -> 8817 bytes .../dark_ambient/images/icons/classical.jpg | Bin 0 -> 8908 bytes .../dark_ambient/images/icons/comedy.jpg | Bin 0 -> 8930 bytes .../dark_ambient/images/icons/comics.jpg | Bin 0 -> 8888 bytes .../dark_ambient/images/icons/country.jpg | Bin 0 -> 8895 bytes .../dark_ambient/images/icons/dance.jpg | Bin 0 -> 8666 bytes .../dark_ambient/images/icons/disco.jpg | Bin 0 -> 8989 bytes .../styles/dark_ambient/images/icons/dnb.jpg | Bin 0 -> 8930 bytes .../dark_ambient/images/icons/ebooksfic.jpg | Bin 0 -> 8884 bytes .../images/icons/ebooksnonfic.jpg | Bin 0 -> 8762 bytes .../dark_ambient/images/icons/electronic.jpg | Bin 0 -> 9107 bytes .../styles/dark_ambient/images/icons/emo.jpg | Bin 0 -> 8871 bytes .../images/icons/experimental.jpg | Bin 0 -> 8673 bytes .../styles/dark_ambient/images/icons/folk.jpg | Bin 0 -> 8743 bytes .../styles/dark_ambient/images/icons/funk.jpg | Bin 0 -> 9072 bytes .../dark_ambient/images/icons/garage.jpg | Bin 0 -> 9037 bytes .../dark_ambient/images/icons/generic.png | Bin 0 -> 472 bytes .../dark_ambient/images/icons/grunge.jpg | Bin 0 -> 8738 bytes .../dark_ambient/images/icons/hardcore.jpg | Bin 0 -> 8741 bytes .../images/icons/hardcoredance.jpg | Bin 0 -> 9036 bytes .../dark_ambient/images/icons/hiphop.jpg | Bin 0 -> 9123 bytes .../dark_ambient/images/icons/house.jpg | Bin 0 -> 8837 bytes .../styles/dark_ambient/images/icons/idm.jpg | Bin 0 -> 8960 bytes .../dark_ambient/images/icons/indie.jpg | Bin 0 -> 8989 bytes .../dark_ambient/images/icons/industrial.jpg | Bin 0 -> 8904 bytes .../styles/dark_ambient/images/icons/jazz.jpg | Bin 0 -> 8979 bytes .../styles/dark_ambient/images/icons/jpop.jpg | Bin 0 -> 8598 bytes .../dark_ambient/images/icons/locked_read.png | Bin 0 -> 489 bytes .../images/icons/locked_sticky_read.png | Bin 0 -> 596 bytes .../images/icons/locked_sticky_unread.png | Bin 0 -> 1067 bytes .../images/icons/locked_unread.png | Bin 0 -> 1154 bytes .../dark_ambient/images/icons/metal.jpg | Bin 0 -> 8964 bytes .../dark_ambient/images/icons/newage.jpg | Bin 0 -> 8776 bytes .../styles/dark_ambient/images/icons/ost.jpg | Bin 0 -> 8930 bytes .../styles/dark_ambient/images/icons/pop.jpg | Bin 0 -> 8991 bytes .../dark_ambient/images/icons/postrock.jpg | Bin 0 -> 9021 bytes .../dark_ambient/images/icons/progrock.jpg | Bin 0 -> 8804 bytes .../dark_ambient/images/icons/psychedelic.jpg | Bin 0 -> 8712 bytes .../dark_ambient/images/icons/psytrance.jpg | Bin 0 -> 8664 bytes .../styles/dark_ambient/images/icons/punk.jpg | Bin 0 -> 9057 bytes .../styles/dark_ambient/images/icons/read.png | Bin 0 -> 202 bytes .../dark_ambient/images/icons/reggae.jpg | Bin 0 -> 8844 bytes .../styles/dark_ambient/images/icons/rnb.jpg | Bin 0 -> 8635 bytes .../styles/dark_ambient/images/icons/rock.jpg | Bin 0 -> 8837 bytes .../styles/dark_ambient/images/icons/ska.jpg | Bin 0 -> 8784 bytes .../styles/dark_ambient/images/icons/soul.jpg | Bin 0 -> 8785 bytes .../dark_ambient/images/icons/sticky_read.png | Bin 0 -> 440 bytes .../images/icons/sticky_unread.png | Bin 0 -> 763 bytes .../dark_ambient/images/icons/techno.jpg | Bin 0 -> 8533 bytes .../dark_ambient/images/icons/trance.jpg | Bin 0 -> 8823 bytes .../dark_ambient/images/icons/triphop.jpg | Bin 0 -> 8652 bytes .../dark_ambient/images/icons/ukgarage.jpg | Bin 0 -> 8908 bytes .../dark_ambient/images/icons/unread.png | Bin 0 -> 467 bytes .../dark_ambient/images/icons/world.jpg | Bin 0 -> 8865 bytes static/styles/dark_ambient/images/inputbg.png | Bin 0 -> 2797 bytes .../styles/dark_ambient/images/leechers.png | Bin 0 -> 210 bytes static/styles/dark_ambient/images/music.png | Bin 0 -> 472 bytes .../styles/dark_ambient/images/poll_left.png | Bin 0 -> 233 bytes .../dark_ambient/images/poll_middle.png | Bin 0 -> 206 bytes .../styles/dark_ambient/images/poll_right.png | Bin 0 -> 255 bytes .../styles/dark_ambient/images/searchbox.png | Bin 0 -> 1950 bytes static/styles/dark_ambient/images/seeders.png | Bin 0 -> 204 bytes static/styles/dark_ambient/images/show.png | Bin 0 -> 805 bytes .../styles/dark_ambient/images/snatched.png | Bin 0 -> 281 bytes static/styles/dark_ambient/images/tags.png | Bin 0 -> 3376 bytes .../styles/dark_ambient/images/what_logo.png | Bin 0 -> 5902 bytes static/styles/dark_ambient/images/wrapper.png | Bin 0 -> 311 bytes static/styles/dark_ambient/style.css | 2001 +++++++++++++++ static/styles/global.css | 175 ++ .../gtfo_spaceship/fonts/aller_rg-webfont.ttf | Bin 0 -> 43064 bytes .../fonts/allerdisplay-webfont.ttf | Bin 0 -> 95616 bytes .../images/chevroni-axxion-down.png | Bin 0 -> 1198 bytes .../images/chevroni-axxion-right.png | Bin 0 -> 1241 bytes .../gtfo_spaceship/images/chevroni-axxion.png | Bin 0 -> 3176 bytes .../images/doppleganger-management.png | Bin 0 -> 1188 bytes .../images/glyphicons_067_bookmark.png | Bin 0 -> 1005 bytes .../images/glyphicons_089_logbook.png | Bin 0 -> 1160 bytes .../images/glyphicons_162_right_arrow.png | Bin 0 -> 1142 bytes .../gtfo_spaceship/images/go_last_read.png | Bin 0 -> 277 bytes .../gtfo_spaceship/images/hey-you-guys-A.png | Bin 0 -> 2653 bytes .../gtfo_spaceship/images/hey-you-guys-F.png | Bin 0 -> 2504 bytes .../gtfo_spaceship/images/hey-you-guys-L.png | Bin 0 -> 2496 bytes .../gtfo_spaceship/images/hey-you-guys-R.png | Bin 0 -> 2656 bytes .../gtfo_spaceship/images/hey-you-guys-T.png | Bin 0 -> 2490 bytes .../gtfo_spaceship/images/hey-you-guys-U.png | Bin 0 -> 2566 bytes .../gtfo_spaceship/images/hey-you-guys.png | Bin 0 -> 2582 bytes .../gtfo_spaceship/images/icanhaztm.png | Bin 0 -> 3346 bytes ...large_read_glyphicons_040_conversation.png | Bin 0 -> 1236 bytes ...rge_unread_glyphicons_040_conversation.png | Bin 0 -> 1200 bytes ...e_unread_glyphicons_040_conversation.png.1 | Bin 0 -> 1200 bytes .../styles/gtfo_spaceship/images/leechers.png | Bin 0 -> 210 bytes .../styles/gtfo_spaceship/images/much-luv.png | Bin 0 -> 3555 bytes .../images/my-dictator-in-a-box-hover.png | Bin 0 -> 6367 bytes .../images/my-dictator-in-a-box.png | Bin 0 -> 2804 bytes .../gtfo_spaceship/images/overlay-button.png | Bin 0 -> 955 bytes .../styles/gtfo_spaceship/images/poll-bg.png | Bin 0 -> 2250 bytes .../styles/gtfo_spaceship/images/poll-end.png | Bin 0 -> 932 bytes .../gtfo_spaceship/images/poll-wide-bg.png | Bin 0 -> 2677 bytes .../gtfo_spaceship/images/prong-dawg.png | Bin 0 -> 4543 bytes .../gtfo_spaceship/images/purple-jizz.jpg | Bin 0 -> 33491 bytes static/styles/gtfo_spaceship/images/quote.png | Bin 0 -> 7383 bytes .../images/read-and-obey-or-else.png | Bin 0 -> 1134 bytes .../styles/gtfo_spaceship/images/seeders.png | Bin 0 -> 204 bytes .../small_locked_read_glyphicons_070_link.png | Bin 0 -> 1210 bytes ...mall_locked_unread_glyphicons_070_link.png | Bin 0 -> 1205 bytes ...small_read_glyphicons_040_conversation.png | Bin 0 -> 1285 bytes .../small_sticky_read_glyphicons_033_star.png | Bin 0 -> 1148 bytes ...mall_sticky_unread_glyphicons_033_star.png | Bin 0 -> 1126 bytes ...all_unread_glyphicons_040_conversation.png | Bin 0 -> 1224 bytes .../styles/gtfo_spaceship/images/snatched.png | Bin 0 -> 281 bytes .../gtfo_spaceship/images/squizzare.png | Bin 0 -> 930 bytes .../gtfo_spaceship/images/vroooooom-done.png | Bin 0 -> 1212 bytes .../styles/gtfo_spaceship/images/who-cd.png | Bin 0 -> 1191 bytes .../images/yo-dawg-i-heard-you-like-cds.png | Bin 0 -> 3668 bytes .../gtfo_spaceship/images/z0mg-look.png | Bin 0 -> 4191 bytes static/styles/gtfo_spaceship/style.css | 1401 ++++++++++ static/styles/hydro/images/apps.png | Bin 0 -> 660 bytes static/styles/hydro/images/audiobook.png | Bin 0 -> 826 bytes static/styles/hydro/images/bar.gif | Bin 0 -> 54 bytes static/styles/hydro/images/bar_left.gif | Bin 0 -> 54 bytes static/styles/hydro/images/bar_right.gif | Bin 0 -> 54 bytes static/styles/hydro/images/bars.gif | Bin 0 -> 224 bytes static/styles/hydro/images/close.png | Bin 0 -> 254 bytes static/styles/hydro/images/colhead-grad.gif | Bin 0 -> 365 bytes static/styles/hydro/images/comedy.png | Bin 0 -> 628 bytes static/styles/hydro/images/comics.png | Bin 0 -> 372 bytes static/styles/hydro/images/ebook.png | Bin 0 -> 861 bytes static/styles/hydro/images/elearning.png | Bin 0 -> 733 bytes static/styles/hydro/images/go_last_read.png | Bin 0 -> 247 bytes static/styles/hydro/images/header.png | Bin 0 -> 237 bytes static/styles/hydro/images/hide.png | Bin 0 -> 225 bytes static/styles/hydro/images/leechers.png | Bin 0 -> 355 bytes static/styles/hydro/images/locked_read.png | Bin 0 -> 734 bytes .../hydro/images/locked_sticky_read.png | Bin 0 -> 689 bytes .../hydro/images/locked_sticky_unread.png | Bin 0 -> 3691 bytes static/styles/hydro/images/locked_unread.png | Bin 0 -> 1021 bytes static/styles/hydro/images/logo.png | Bin 0 -> 18525 bytes static/styles/hydro/images/music.png | Bin 0 -> 472 bytes static/styles/hydro/images/open.png | Bin 0 -> 244 bytes static/styles/hydro/images/read.png | Bin 0 -> 308 bytes static/styles/hydro/images/seeders.png | Bin 0 -> 295 bytes static/styles/hydro/images/show.png | Bin 0 -> 223 bytes static/styles/hydro/images/snatched.png | Bin 0 -> 329 bytes static/styles/hydro/images/sticky_read.png | Bin 0 -> 463 bytes static/styles/hydro/images/sticky_unread.png | Bin 0 -> 3363 bytes static/styles/hydro/images/unread.png | Bin 0 -> 3128 bytes static/styles/hydro/style.css | 774 ++++++ static/styles/kuro/images/apps.png | Bin 0 -> 660 bytes static/styles/kuro/images/audiobook.png | Bin 0 -> 826 bytes static/styles/kuro/images/bar.gif | Bin 0 -> 54 bytes static/styles/kuro/images/bar_left.gif | Bin 0 -> 54 bytes static/styles/kuro/images/bar_right.gif | Bin 0 -> 54 bytes static/styles/kuro/images/comedy.png | Bin 0 -> 628 bytes static/styles/kuro/images/comics.png | Bin 0 -> 372 bytes static/styles/kuro/images/ebook.png | Bin 0 -> 861 bytes static/styles/kuro/images/elearning.png | Bin 0 -> 733 bytes static/styles/kuro/images/go_last_read.png | Bin 0 -> 256 bytes static/styles/kuro/images/hide.png | Bin 0 -> 232 bytes static/styles/kuro/images/leechers.png | Bin 0 -> 210 bytes static/styles/kuro/images/locked_read.png | Bin 0 -> 3191 bytes static/styles/kuro/images/locked_sticky.png | Bin 0 -> 3717 bytes .../styles/kuro/images/locked_sticky_read.png | Bin 0 -> 576 bytes .../kuro/images/locked_sticky_unread.png | Bin 0 -> 836 bytes static/styles/kuro/images/locked_unread.png | Bin 0 -> 3569 bytes static/styles/kuro/images/logo.png | Bin 0 -> 7953 bytes static/styles/kuro/images/music.png | Bin 0 -> 472 bytes static/styles/kuro/images/read.png | Bin 0 -> 308 bytes static/styles/kuro/images/seeders.png | Bin 0 -> 204 bytes static/styles/kuro/images/show.png | Bin 0 -> 328 bytes static/styles/kuro/images/snatched.png | Bin 0 -> 281 bytes static/styles/kuro/images/sticky.png | Bin 0 -> 522 bytes static/styles/kuro/images/sticky_read.png | Bin 0 -> 456 bytes static/styles/kuro/images/sticky_unread.png | Bin 0 -> 597 bytes static/styles/kuro/images/unread.png | Bin 0 -> 3128 bytes static/styles/kuro/style.css | 885 +++++++ static/styles/layer_cake/images/apps.png | Bin 0 -> 660 bytes static/styles/layer_cake/images/audiobook.png | Bin 0 -> 826 bytes static/styles/layer_cake/images/auto.png | Bin 0 -> 492 bytes static/styles/layer_cake/images/bar.gif | Bin 0 -> 54 bytes static/styles/layer_cake/images/bar_left.gif | Bin 0 -> 54 bytes static/styles/layer_cake/images/bar_right.gif | Bin 0 -> 54 bytes static/styles/layer_cake/images/comedy.png | Bin 0 -> 628 bytes static/styles/layer_cake/images/comics.png | Bin 0 -> 372 bytes static/styles/layer_cake/images/ebook.png | Bin 0 -> 861 bytes static/styles/layer_cake/images/elearning.png | Bin 0 -> 733 bytes .../styles/layer_cake/images/go_last_read.png | Bin 0 -> 245 bytes .../layer_cake/images/grayarrow_close.png | Bin 0 -> 254 bytes .../layer_cake/images/grayarrow_open.png | Bin 0 -> 244 bytes static/styles/layer_cake/images/headerbg.png | Bin 0 -> 170 bytes static/styles/layer_cake/images/hide.png | Bin 0 -> 232 bytes static/styles/layer_cake/images/leechers.png | Bin 0 -> 210 bytes .../styles/layer_cake/images/locked_read.png | Bin 0 -> 734 bytes .../layer_cake/images/locked_sticky_read.png | Bin 0 -> 689 bytes .../images/locked_sticky_unread.png | Bin 0 -> 3691 bytes .../layer_cake/images/locked_unread.png | Bin 0 -> 1021 bytes static/styles/layer_cake/images/logo.png | Bin 0 -> 30962 bytes static/styles/layer_cake/images/messages.gif | Bin 0 -> 91 bytes static/styles/layer_cake/images/music.png | Bin 0 -> 472 bytes .../styles/layer_cake/images/newmessages.gif | Bin 0 -> 99 bytes static/styles/layer_cake/images/read.png | Bin 0 -> 308 bytes static/styles/layer_cake/images/seeders.png | Bin 0 -> 204 bytes static/styles/layer_cake/images/show.png | Bin 0 -> 328 bytes static/styles/layer_cake/images/snatched.png | Bin 0 -> 281 bytes .../styles/layer_cake/images/sticky_read.png | Bin 0 -> 463 bytes .../layer_cake/images/sticky_unread.png | Bin 0 -> 3363 bytes static/styles/layer_cake/images/unread.png | Bin 0 -> 3128 bytes static/styles/layer_cake/style.css | 778 ++++++ static/styles/layer_cake/style2.css | 744 ++++++ static/styles/log.css | 45 + .../styles/minimal/images/balloon-unread.png | Bin 0 -> 658 bytes static/styles/minimal/images/balloon.png | Bin 0 -> 696 bytes static/styles/minimal/images/bg.png | Bin 0 -> 3047 bytes static/styles/minimal/images/blockquote.png | Bin 0 -> 144 bytes static/styles/minimal/images/go_last_read.png | Bin 0 -> 3211 bytes static/styles/minimal/images/icons/apps.png | Bin 0 -> 660 bytes .../styles/minimal/images/icons/audiobook.png | Bin 0 -> 826 bytes static/styles/minimal/images/icons/comedy.png | Bin 0 -> 628 bytes static/styles/minimal/images/icons/comics.png | Bin 0 -> 372 bytes static/styles/minimal/images/icons/ebook.png | Bin 0 -> 861 bytes .../styles/minimal/images/icons/elearning.png | Bin 0 -> 733 bytes static/styles/minimal/images/icons/music.png | Bin 0 -> 472 bytes static/styles/minimal/images/leechers.png | Bin 0 -> 210 bytes .../minimal/images/lock-sticky-unread.png | Bin 0 -> 588 bytes static/styles/minimal/images/lock-sticky.png | Bin 0 -> 546 bytes static/styles/minimal/images/lock-unread.png | Bin 0 -> 608 bytes static/styles/minimal/images/lock.png | Bin 0 -> 596 bytes static/styles/minimal/images/logo.png | Bin 0 -> 12502 bytes static/styles/minimal/images/poll_left.png | Bin 0 -> 3087 bytes static/styles/minimal/images/poll_middle.png | Bin 0 -> 2850 bytes static/styles/minimal/images/poll_right.png | Bin 0 -> 3166 bytes static/styles/minimal/images/seeders.png | Bin 0 -> 204 bytes static/styles/minimal/images/snatched.png | Bin 0 -> 281 bytes static/styles/minimal/images/sprite.png | Bin 0 -> 25458 bytes .../styles/minimal/images/sticky-unread.png | Bin 0 -> 435 bytes static/styles/minimal/images/sticky.png | Bin 0 -> 400 bytes static/styles/minimal/images/unread.png | Bin 0 -> 554 bytes static/styles/minimal/style.css | 539 ++++ static/styles/minimal/style2.css | 467 ++++ static/styles/minimal_mod_alt.css | 1418 +++++++++++ static/styles/mono/icons/applications.png | Bin 0 -> 418 bytes static/styles/mono/icons/audiobooks.png | Bin 0 -> 419 bytes static/styles/mono/icons/comedy.png | Bin 0 -> 359 bytes static/styles/mono/icons/comics.png | Bin 0 -> 424 bytes static/styles/mono/icons/ebooks.png | Bin 0 -> 424 bytes static/styles/mono/icons/elearning.png | Bin 0 -> 346 bytes static/styles/mono/icons/goto.png | Bin 0 -> 3099 bytes static/styles/mono/icons/music.png | Bin 0 -> 346 bytes static/styles/mono/icons/quote-mark.png | Bin 0 -> 3664 bytes static/styles/mono/icons/read-locked.png | Bin 0 -> 338 bytes static/styles/mono/icons/read.png | Bin 0 -> 262 bytes static/styles/mono/icons/show-hide.png | Bin 0 -> 3010 bytes .../styles/mono/icons/sticky-read-locked.png | Bin 0 -> 431 bytes static/styles/mono/icons/sticky-read.png | Bin 0 -> 363 bytes .../mono/icons/sticky-unread-locked.png | Bin 0 -> 448 bytes static/styles/mono/icons/sticky-unread.png | Bin 0 -> 383 bytes static/styles/mono/icons/unread.png | Bin 0 -> 269 bytes static/styles/mono/images/leechers.png | Bin 0 -> 210 bytes static/styles/mono/images/seeders.png | Bin 0 -> 204 bytes static/styles/mono/images/snatched.png | Bin 0 -> 281 bytes static/styles/mono/style.css | 1176 +++++++++ static/styles/postmod.zip | Bin 0 -> 2976163 bytes static/styles/postmod/images/Akzidenz.otf | Bin 0 -> 31440 bytes static/styles/postmod/images/Anonymous.ttf | 3 + static/styles/postmod/images/Avant.otf | Bin 0 -> 32760 bytes static/styles/postmod/images/CorpidOffice.ttf | Bin 0 -> 101416 bytes static/styles/postmod/images/Officina.otf | Bin 0 -> 35440 bytes .../styles/postmod/images/alert-overlay.png | Bin 0 -> 135 bytes static/styles/postmod/images/bg_footer.png | Bin 0 -> 2944 bytes static/styles/postmod/images/bg_header.png | Bin 0 -> 145 bytes static/styles/postmod/images/bg_inputs.png | Bin 0 -> 284 bytes static/styles/postmod/images/bg_menu.png | Bin 0 -> 3082 bytes static/styles/postmod/images/body.jpg | Bin 0 -> 7313 bytes static/styles/postmod/images/content.png | Bin 0 -> 2804 bytes .../styles/postmod/images/content_light.png | Bin 0 -> 192 bytes static/styles/postmod/images/external.png | Bin 0 -> 178 bytes static/styles/postmod/images/gazelle.png | Bin 0 -> 4256 bytes static/styles/postmod/images/go_last_read.png | Bin 0 -> 3209 bytes static/styles/postmod/images/hide.png | Bin 0 -> 122 bytes static/styles/postmod/images/leechers.png | Bin 0 -> 210 bytes static/styles/postmod/images/load.gif | Bin 0 -> 723 bytes static/styles/postmod/images/locked_read.png | Bin 0 -> 596 bytes .../postmod/images/locked_sticky_read.png | Bin 0 -> 546 bytes .../postmod/images/locked_sticky_unread.png | Bin 0 -> 3228 bytes .../styles/postmod/images/locked_unread.png | Bin 0 -> 608 bytes static/styles/postmod/images/logo.png | Bin 0 -> 1457 bytes static/styles/postmod/images/nav_matrix.png | Bin 0 -> 8988 bytes .../postmod/images/nav_matrix_extended.png | Bin 0 -> 19434 bytes .../styles/postmod/images/nu_nav_matrix.png | Bin 0 -> 38402 bytes static/styles/postmod/images/poll_left.png | Bin 0 -> 3087 bytes static/styles/postmod/images/poll_middle.png | Bin 0 -> 2850 bytes static/styles/postmod/images/poll_right.png | Bin 0 -> 3166 bytes static/styles/postmod/images/read.png | Bin 0 -> 696 bytes static/styles/postmod/images/seeders.png | Bin 0 -> 204 bytes static/styles/postmod/images/show.png | Bin 0 -> 127 bytes static/styles/postmod/images/snatched.png | Bin 0 -> 281 bytes static/styles/postmod/images/sticky_read.png | Bin 0 -> 400 bytes .../styles/postmod/images/sticky_unread.png | Bin 0 -> 3072 bytes static/styles/postmod/images/table_header.png | Bin 0 -> 462 bytes .../postmod/images/table_header_dark.png | Bin 0 -> 356 bytes static/styles/postmod/images/unread.png | Bin 0 -> 3301 bytes static/styles/postmod/images/wood.jpg | Bin 0 -> 514011 bytes static/styles/postmod/images/woodlogo.png | Bin 0 -> 4216 bytes static/styles/postmod/images/wrapper.png | Bin 0 -> 761603 bytes static/styles/postmod/map.html | 3 + static/styles/postmod/style.css | 1035 ++++++++ static/styles/proton/images/apps.png | Bin 0 -> 660 bytes static/styles/proton/images/audiobook.png | Bin 0 -> 826 bytes static/styles/proton/images/category/apps.png | Bin 0 -> 978 bytes .../proton/images/category/audiobook.png | Bin 0 -> 1180 bytes .../styles/proton/images/category/comedy.png | Bin 0 -> 1057 bytes .../styles/proton/images/category/comics.png | Bin 0 -> 818 bytes .../styles/proton/images/category/ebook.png | Bin 0 -> 1051 bytes .../proton/images/category/elearning.png | Bin 0 -> 1123 bytes .../styles/proton/images/category/music.png | Bin 0 -> 901 bytes static/styles/proton/images/closebox.png | Bin 0 -> 1910 bytes static/styles/proton/images/comedy.png | Bin 0 -> 628 bytes static/styles/proton/images/comics.png | Bin 0 -> 372 bytes static/styles/proton/images/convo.png | Bin 0 -> 1022 bytes static/styles/proton/images/discogbglight.png | Bin 0 -> 215 bytes .../proton/images/discogbglightshadow.png | Bin 0 -> 137 bytes static/styles/proton/images/dl.png | Bin 0 -> 395 bytes static/styles/proton/images/download.png | Bin 0 -> 33488 bytes .../styles/proton/images/download_bottom.png | Bin 0 -> 973 bytes static/styles/proton/images/ebook.png | Bin 0 -> 861 bytes static/styles/proton/images/elearning.png | Bin 0 -> 733 bytes static/styles/proton/images/filter.png | Bin 0 -> 43233 bytes static/styles/proton/images/footer_bg.png | Bin 0 -> 141 bytes static/styles/proton/images/forum_postbg.png | Bin 0 -> 125 bytes .../proton/images/forum_postbgspeech1.png | Bin 0 -> 1076 bytes .../proton/images/forum_postbgspeech2.png | Bin 0 -> 169 bytes .../proton/images/forum_postbgspeech3.png | Bin 0 -> 400 bytes .../styles/proton/images/forum_postbodybg.png | Bin 0 -> 119 bytes .../proton/images/forums/go_last_read.png | Bin 0 -> 277 bytes .../proton/images/forums/locked_read.gif | Bin 0 -> 146 bytes .../images/forums/locked_sticky_read.gif | Bin 0 -> 181 bytes .../images/forums/locked_sticky_unread.gif | Bin 0 -> 181 bytes .../proton/images/forums/locked_unread.gif | Bin 0 -> 146 bytes static/styles/proton/images/forums/read.gif | Bin 0 -> 139 bytes .../proton/images/forums/sticky_read.gif | Bin 0 -> 132 bytes .../proton/images/forums/sticky_unread.gif | Bin 0 -> 132 bytes static/styles/proton/images/forums/unread.gif | Bin 0 -> 225 bytes static/styles/proton/images/go_last_read.png | Bin 0 -> 277 bytes static/styles/proton/images/inputbg.png | Bin 0 -> 123 bytes static/styles/proton/images/leechers.png | Bin 0 -> 210 bytes static/styles/proton/images/locked.png | Bin 0 -> 3807 bytes static/styles/proton/images/locked_read.gif | Bin 0 -> 146 bytes static/styles/proton/images/locked_read.png | Bin 0 -> 734 bytes static/styles/proton/images/locked_sticky.png | Bin 0 -> 3717 bytes .../proton/images/locked_sticky_read.gif | Bin 0 -> 181 bytes .../proton/images/locked_sticky_read.png | Bin 0 -> 689 bytes .../proton/images/locked_sticky_unread.gif | Bin 0 -> 181 bytes .../proton/images/locked_sticky_unread.png | Bin 0 -> 3691 bytes static/styles/proton/images/locked_unread.gif | Bin 0 -> 146 bytes static/styles/proton/images/locked_unread.png | Bin 0 -> 1021 bytes static/styles/proton/images/music.png | Bin 0 -> 472 bytes static/styles/proton/images/poll_left.png | Bin 0 -> 407 bytes static/styles/proton/images/poll_middle.png | Bin 0 -> 181 bytes static/styles/proton/images/poll_right.png | Bin 0 -> 497 bytes .../styles/proton/images/proton18052010.zip | Bin 0 -> 104851 bytes static/styles/proton/images/quote_bg.png | Bin 0 -> 888 bytes static/styles/proton/images/read.gif | Bin 0 -> 139 bytes static/styles/proton/images/read.png | Bin 0 -> 308 bytes static/styles/proton/images/searchbox.png | Bin 0 -> 1549 bytes static/styles/proton/images/seeders.png | Bin 0 -> 204 bytes static/styles/proton/images/snatched.png | Bin 0 -> 281 bytes static/styles/proton/images/sticky.png | Bin 0 -> 3388 bytes static/styles/proton/images/sticky_read.gif | Bin 0 -> 132 bytes static/styles/proton/images/sticky_read.png | Bin 0 -> 463 bytes static/styles/proton/images/sticky_unread.gif | Bin 0 -> 132 bytes static/styles/proton/images/sticky_unread.png | Bin 0 -> 3363 bytes static/styles/proton/images/tags.png | Bin 0 -> 666 bytes static/styles/proton/images/unread.gif | Bin 0 -> 139 bytes static/styles/proton/images/unread.png | Bin 0 -> 3128 bytes static/styles/proton/images/what_bg.gif | Bin 0 -> 99 bytes static/styles/proton/images/what_bg.jpg | Bin 0 -> 3626 bytes static/styles/proton/images/what_head3.jpg | Bin 0 -> 4695 bytes .../proton/images/what_head3_shadow.jpg | Bin 0 -> 14861 bytes static/styles/proton/images/what_hide.gif | Bin 0 -> 130 bytes static/styles/proton/images/what_hide.png | Bin 0 -> 784 bytes static/styles/proton/images/what_logo.png | Bin 0 -> 5902 bytes static/styles/proton/images/what_show.gif | Bin 0 -> 153 bytes static/styles/proton/images/what_show.png | Bin 0 -> 995 bytes static/styles/proton/style.css | 1731 +++++++++++++ static/styles/public/images/bg.png | Bin 0 -> 238 bytes static/styles/public/images/footer.png | Bin 0 -> 622 bytes static/styles/public/images/logo.png | Bin 0 -> 4681 bytes static/styles/public/images/sprite.png | Bin 0 -> 5666 bytes static/styles/public/images/watermark.png | Bin 0 -> 424 bytes static/styles/public/style.css | 119 + static/styles/shiro/images/apps.png | Bin 0 -> 660 bytes static/styles/shiro/images/audiobook.png | Bin 0 -> 826 bytes static/styles/shiro/images/auto.png | Bin 0 -> 492 bytes static/styles/shiro/images/bar.gif | Bin 0 -> 54 bytes static/styles/shiro/images/bar_left.gif | Bin 0 -> 54 bytes static/styles/shiro/images/bar_right.gif | Bin 0 -> 54 bytes static/styles/shiro/images/close.png | Bin 0 -> 254 bytes static/styles/shiro/images/comedy.png | Bin 0 -> 628 bytes static/styles/shiro/images/comics.png | Bin 0 -> 372 bytes static/styles/shiro/images/ebook.png | Bin 0 -> 861 bytes static/styles/shiro/images/elearning.png | Bin 0 -> 733 bytes static/styles/shiro/images/go_last_read.png | Bin 0 -> 245 bytes static/styles/shiro/images/hide.png | Bin 0 -> 232 bytes static/styles/shiro/images/leechers.png | Bin 0 -> 210 bytes static/styles/shiro/images/locked_read.png | Bin 0 -> 734 bytes .../shiro/images/locked_sticky_read.png | Bin 0 -> 689 bytes .../shiro/images/locked_sticky_unread.png | Bin 0 -> 3691 bytes static/styles/shiro/images/locked_unread.png | Bin 0 -> 1021 bytes static/styles/shiro/images/logo.png | Bin 0 -> 6987 bytes static/styles/shiro/images/music.png | Bin 0 -> 472 bytes static/styles/shiro/images/open.png | Bin 0 -> 244 bytes static/styles/shiro/images/read.png | Bin 0 -> 308 bytes static/styles/shiro/images/seeders.png | Bin 0 -> 204 bytes static/styles/shiro/images/show.png | Bin 0 -> 328 bytes static/styles/shiro/images/snatched.png | Bin 0 -> 281 bytes static/styles/shiro/images/sticky_read.png | Bin 0 -> 463 bytes static/styles/shiro/images/sticky_unread.png | Bin 0 -> 3363 bytes static/styles/shiro/images/unread.png | Bin 0 -> 3128 bytes static/styles/shiro/style.css | 860 +++++++ static/styles/whatlove/images/apps.png | Bin 0 -> 660 bytes static/styles/whatlove/images/audiobook.png | Bin 0 -> 826 bytes static/styles/whatlove/images/bar.gif | Bin 0 -> 54 bytes static/styles/whatlove/images/bar_left.gif | Bin 0 -> 54 bytes static/styles/whatlove/images/bar_right.gif | Bin 0 -> 54 bytes static/styles/whatlove/images/bg.png | Bin 0 -> 384 bytes static/styles/whatlove/images/comedy.png | Bin 0 -> 628 bytes static/styles/whatlove/images/comics.png | Bin 0 -> 372 bytes static/styles/whatlove/images/ebook.png | Bin 0 -> 861 bytes static/styles/whatlove/images/elearning.png | Bin 0 -> 733 bytes .../styles/whatlove/images/go_last_read.png | Bin 0 -> 277 bytes static/styles/whatlove/images/hide.png | Bin 0 -> 241 bytes static/styles/whatlove/images/leechers.png | Bin 0 -> 268 bytes static/styles/whatlove/images/locked_read.png | Bin 0 -> 490 bytes .../whatlove/images/locked_sticky_read.png | Bin 0 -> 576 bytes .../whatlove/images/locked_sticky_unread.png | Bin 0 -> 836 bytes .../styles/whatlove/images/locked_unread.png | Bin 0 -> 1088 bytes static/styles/whatlove/images/logo.png | Bin 0 -> 2107 bytes static/styles/whatlove/images/music.png | Bin 0 -> 472 bytes static/styles/whatlove/images/read.png | Bin 0 -> 210 bytes static/styles/whatlove/images/seeders.png | Bin 0 -> 267 bytes static/styles/whatlove/images/show.png | Bin 0 -> 420 bytes static/styles/whatlove/images/snatched.png | Bin 0 -> 1012 bytes static/styles/whatlove/images/sticky_read.png | Bin 0 -> 456 bytes .../styles/whatlove/images/sticky_unread.png | Bin 0 -> 597 bytes static/styles/whatlove/images/unread.png | Bin 0 -> 515 bytes static/styles/whatlove/style.css | 892 +++++++ .../styles/white.cd/images/go_last_read.png | Bin 0 -> 162 bytes static/styles/white.cd/images/header.png | Bin 0 -> 181 bytes static/styles/white.cd/images/icons.png | Bin 0 -> 784 bytes static/styles/white.cd/images/leechers.png | Bin 0 -> 2913 bytes static/styles/white.cd/images/logo.png | Bin 0 -> 923 bytes static/styles/white.cd/images/seeders.png | Bin 0 -> 2918 bytes static/styles/white.cd/images/snatched.png | Bin 0 -> 2982 bytes static/styles/white.cd/style.css | 22 + stats.php | 1 + templates/error.tpl | 48 + templates/invite.tpl | 12 + templates/new_registration.tpl | 8 + templates/password_reset.tpl | 11 + tools.php | 3 + top10.php | 1 + torrents.php | 3 + upgrade.php | 3 + upload.php | 3 + user.php | 3 + userhistory.php | 3 + watchlist.php | 3 + whitelist.php | 2 + wiki.php | 3 + 1182 files changed, 85184 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGES.txt create mode 100644 COPYING.txt create mode 100644 INSTALL.txt create mode 100644 ajax.php create mode 100644 announce.php create mode 100644 api.php create mode 100644 artist.php create mode 100644 better.php create mode 100644 block_04097.html create mode 100644 blog.php create mode 100644 bookmarks.php create mode 100644 browse.php create mode 100644 captcha.php create mode 100644 captcha/captcha1.png create mode 100644 captcha/captcha2.png create mode 100644 captcha/captcha3.png create mode 100644 captcha/captcha4.png create mode 100644 captcha/captcha5.png create mode 100644 captcha/captcha6.png create mode 100644 captcha/captcha7.png create mode 100644 captcha/captcha8.png create mode 100644 captcha/captcha9.png create mode 100644 chat.php create mode 100644 cheaters.php create mode 100644 classes/ajax_start.php create mode 100644 classes/class_alias.php create mode 100644 classes/class_artist.php create mode 100644 classes/class_artists_similar.php create mode 100644 classes/class_cache.php create mode 100644 classes/class_charts.php create mode 100644 classes/class_cookie.php create mode 100644 classes/class_debug.php create mode 100644 classes/class_encrypt.php create mode 100644 classes/class_feed.php create mode 100644 classes/class_image.php create mode 100644 classes/class_invite_tree.php create mode 100644 classes/class_irc.php create mode 100644 classes/class_mysql.php create mode 100644 classes/class_paranoia.php create mode 100644 classes/class_proxies.php create mode 100644 classes/class_search.php create mode 100644 classes/class_templates.php create mode 100644 classes/class_text.php create mode 100644 classes/class_text2.php create mode 100644 classes/class_text3.php create mode 100644 classes/class_time.php create mode 100644 classes/class_torrent.php create mode 100644 classes/class_torrent_32bit.php create mode 100644 classes/class_torrent_form.php create mode 100644 classes/class_user_rank.php create mode 100644 classes/class_useragent.php create mode 100644 classes/class_validate.php create mode 100644 classes/class_wiki.php create mode 100644 classes/class_zip.php create mode 100644 classes/config.template create mode 100644 classes/fonts/ARIBLK.TTF create mode 100644 classes/fonts/COMIC.TTF create mode 100644 classes/fonts/COMICBD.TTF create mode 100644 classes/fonts/GEORGIA.TTF create mode 100644 classes/fonts/GEORGIAB.TTF create mode 100644 classes/fonts/GEORGIAI.TTF create mode 100644 classes/fonts/GEORGIAZ.TTF create mode 100644 classes/fonts/IMPACT.TTF create mode 100644 classes/fonts/MISTRAL.TTF create mode 100644 classes/fonts/README.TXT create mode 100644 classes/fonts/TREBUC.TTF create mode 100644 classes/fonts/TREBUCBD.TTF create mode 100644 classes/fonts/TREBUCBI.TTF create mode 100644 classes/fonts/TREBUCIT.TTF create mode 100644 classes/fonts/VERDANA.TTF create mode 100644 classes/fonts/VERDANAB.TTF create mode 100644 classes/fonts/VERDANAI.TTF create mode 100644 classes/fonts/VERDANAZ.TTF create mode 100644 classes/permissions_form.php create mode 100644 classes/regex.php create mode 100644 classes/script_start.php create mode 100644 classes/sphinxapi.php create mode 100644 collage.php create mode 100644 collages.php create mode 100644 comments.php create mode 100644 delays.php create mode 100644 design/privatefooter.php create mode 100644 design/privateheader.php create mode 100644 design/publicfooter.php create mode 100644 design/publicheader.php create mode 100644 donate.php create mode 100644 error.php create mode 100644 favicon.ico create mode 100644 feeds.php create mode 100644 flush.php create mode 100644 forums.php create mode 100644 friends.php create mode 100644 gazelle.sql create mode 100644 image.php create mode 100644 inbox.php create mode 100644 index.php create mode 100644 irc.php create mode 100644 irc_raw.php create mode 100644 log.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 opensearch.php create mode 100644 peerupdate.php create mode 100644 register.php create mode 100644 reports.php create mode 100644 reportsv2.php create mode 100644 requests.php create mode 100644 robots.txt create mode 100644 rules.php create mode 100644 schedule.php create mode 100644 scrape.php create mode 100644 sections/ajax/announcements.php create mode 100644 sections/ajax/artist.php create mode 100644 sections/ajax/better/index.php create mode 100644 sections/ajax/better/single.php create mode 100644 sections/ajax/better/transcode.php create mode 100644 sections/ajax/bookmarks.php create mode 100644 sections/ajax/bookmarks/artists.php create mode 100644 sections/ajax/bookmarks/index.php create mode 100644 sections/ajax/bookmarks/torrents.php create mode 100644 sections/ajax/browse.php create mode 100644 sections/ajax/forum/forum.php create mode 100644 sections/ajax/forum/index.php create mode 100644 sections/ajax/forum/main.php create mode 100644 sections/ajax/forum/thread.php create mode 100644 sections/ajax/giveback_report.php create mode 100644 sections/ajax/grab_report.php create mode 100644 sections/ajax/inbox/inbox.php create mode 100644 sections/ajax/inbox/index.php create mode 100644 sections/ajax/inbox/viewconv.php create mode 100644 sections/ajax/index.php create mode 100644 sections/ajax/info.php create mode 100644 sections/ajax/loadavg.php create mode 100644 sections/ajax/notifications.php create mode 100644 sections/ajax/preview.php create mode 100644 sections/ajax/request.php create mode 100644 sections/ajax/requests.php create mode 100644 sections/ajax/stats.php create mode 100644 sections/ajax/subscriptions.php create mode 100644 sections/ajax/top10/index.php create mode 100644 sections/ajax/top10/tags.php create mode 100644 sections/ajax/top10/torrents.php create mode 100644 sections/ajax/top10/users.php create mode 100644 sections/ajax/torrentgroup.php create mode 100644 sections/ajax/upload.php create mode 100644 sections/ajax/user.php create mode 100644 sections/ajax/usersearch.php create mode 100644 sections/api/access_state.php create mode 100644 sections/api/index.php create mode 100644 sections/artist/add_alias.php create mode 100644 sections/artist/add_similar.php create mode 100644 sections/artist/artist.php create mode 100644 sections/artist/artist_rearrange.php create mode 100644 sections/artist/autocomplete.php create mode 100644 sections/artist/delete.php create mode 100644 sections/artist/delete_alias.php create mode 100644 sections/artist/delete_similar.php create mode 100644 sections/artist/download.php create mode 100644 sections/artist/edit.php create mode 100644 sections/artist/history.php create mode 100644 sections/artist/index.php create mode 100644 sections/artist/notify.php create mode 100644 sections/artist/notifyremove.php create mode 100644 sections/artist/rename.php create mode 100644 sections/artist/takeedit.php create mode 100644 sections/artist/vote_similar.php create mode 100644 sections/better/better.php create mode 100644 sections/better/files.php create mode 100644 sections/better/folders.php create mode 100644 sections/better/index.php create mode 100644 sections/better/single.php create mode 100644 sections/better/snatch.php create mode 100644 sections/better/tags.php create mode 100644 sections/better/transcode.php create mode 100644 sections/better/upload.php create mode 100644 sections/blog/index.php create mode 100644 sections/bookmarks/add.php create mode 100644 sections/bookmarks/artists.php create mode 100644 sections/bookmarks/functions.php create mode 100644 sections/bookmarks/index.php create mode 100644 sections/bookmarks/remove.php create mode 100644 sections/bookmarks/torrents.php create mode 100644 sections/captcha/index.php create mode 100644 sections/chat/index.php create mode 100644 sections/collages/add_comment.php create mode 100644 sections/collages/add_torrent.php create mode 100644 sections/collages/all_comments.php create mode 100644 sections/collages/browse.php create mode 100644 sections/collages/collage.php create mode 100644 sections/collages/delete.php create mode 100644 sections/collages/delete_comment.php create mode 100644 sections/collages/download.php create mode 100644 sections/collages/edit.php create mode 100644 sections/collages/edit_handle.php create mode 100644 sections/collages/get_post.php create mode 100644 sections/collages/index.php create mode 100644 sections/collages/manage.php create mode 100644 sections/collages/manage_handle.php create mode 100644 sections/collages/new.php create mode 100644 sections/collages/new_handle.php create mode 100644 sections/collages/recover.php create mode 100644 sections/collages/take_delete.php create mode 100644 sections/collages/takeedit_comment.php create mode 100644 sections/comments/index.php create mode 100644 sections/donate/cancel.php create mode 100644 sections/donate/complete.php create mode 100644 sections/donate/donate.php create mode 100644 sections/donate/donate_gpal.php create mode 100644 sections/donate/index.php create mode 100644 sections/donate/ipn.php create mode 100644 sections/error/403.php create mode 100644 sections/error/404.php create mode 100644 sections/error/413.php create mode 100644 sections/error/504.php create mode 100644 sections/error/index.php create mode 100644 sections/feeds/index.php create mode 100644 sections/forums/add_poll_option.php create mode 100644 sections/forums/ajax_get_edit.php create mode 100644 sections/forums/catchup.php create mode 100644 sections/forums/change_vote.php create mode 100644 sections/forums/delete.php create mode 100644 sections/forums/delete_poll_option.php create mode 100644 sections/forums/edit_rules.php create mode 100644 sections/forums/forum.php create mode 100644 sections/forums/functions.php create mode 100644 sections/forums/get_post.php create mode 100644 sections/forums/index.php create mode 100644 sections/forums/main.php create mode 100644 sections/forums/mod_thread.php create mode 100644 sections/forums/newthread.php create mode 100644 sections/forums/poll_mod.php create mode 100644 sections/forums/poll_vote.php create mode 100644 sections/forums/search.php create mode 100644 sections/forums/sticky_post.php create mode 100644 sections/forums/take_new_thread.php create mode 100644 sections/forums/take_reply.php create mode 100644 sections/forums/takeedit.php create mode 100644 sections/forums/thread.php create mode 100644 sections/friends/add.php create mode 100644 sections/friends/comment.php create mode 100644 sections/friends/friends.php create mode 100644 sections/friends/index.php create mode 100644 sections/friends/remove.php create mode 100644 sections/image/badprotocol.gif create mode 100644 sections/image/forbidden.gif create mode 100644 sections/image/index.php create mode 100644 sections/image/invalid.gif create mode 100644 sections/image/invisible.gif create mode 100644 sections/image/nogd.gif create mode 100644 sections/image/small.gif create mode 100644 sections/image/timeout.gif create mode 100644 sections/inbox/compose.php create mode 100644 sections/inbox/conversation.php create mode 100644 sections/inbox/forward.php create mode 100644 sections/inbox/get_post.php create mode 100644 sections/inbox/inbox.php create mode 100644 sections/inbox/index.php create mode 100644 sections/inbox/massdelete_handle.php create mode 100644 sections/inbox/takecompose.php create mode 100644 sections/inbox/takeedit.php create mode 100644 sections/index/index.php create mode 100644 sections/index/private.php create mode 100644 sections/index/public.php create mode 100644 sections/irc/index.php create mode 100644 sections/log/index.php create mode 100644 sections/login/disabled.php create mode 100644 sections/login/index.php create mode 100644 sections/login/login.php create mode 100644 sections/login/recover_step1.php create mode 100644 sections/login/recover_step2.php create mode 100644 sections/logout/index.php create mode 100644 sections/peerupdate/index.php create mode 100644 sections/register/closed.php create mode 100644 sections/register/code.php create mode 100644 sections/register/index.php create mode 100644 sections/register/step1.php create mode 100644 sections/register/step2.php create mode 100644 sections/reports/array.php create mode 100644 sections/reports/index.php create mode 100644 sections/reports/report.php create mode 100644 sections/reports/reports.php create mode 100644 sections/reports/stats.php create mode 100644 sections/reports/takereport.php create mode 100644 sections/reports/takeresolve.php create mode 100644 sections/reportsv2/ajax_change_resolve.php create mode 100644 sections/reportsv2/ajax_create_report.php create mode 100644 sections/reportsv2/ajax_grab_report.php create mode 100644 sections/reportsv2/ajax_new_report.php create mode 100644 sections/reportsv2/ajax_report.php create mode 100644 sections/reportsv2/ajax_take_pm.php create mode 100644 sections/reportsv2/ajax_update_comment.php create mode 100644 sections/reportsv2/ajax_update_resolve.php create mode 100644 sections/reportsv2/array.php create mode 100644 sections/reportsv2/header.php create mode 100644 sections/reportsv2/index.php create mode 100644 sections/reportsv2/report.php create mode 100644 sections/reportsv2/reports.php create mode 100644 sections/reportsv2/search.php create mode 100644 sections/reportsv2/static.php create mode 100644 sections/reportsv2/takereport.php create mode 100644 sections/reportsv2/takeresolve.php create mode 100644 sections/reportsv2/views.php create mode 100644 sections/requests/functions.php create mode 100644 sections/requests/index.php create mode 100644 sections/requests/interim.php create mode 100644 sections/requests/new_edit.php create mode 100644 sections/requests/request.php create mode 100644 sections/requests/requests.php create mode 100644 sections/requests/requests.php.presphinx create mode 100644 sections/requests/takedelete.php create mode 100644 sections/requests/takefill.php create mode 100644 sections/requests/takenew_edit.php create mode 100644 sections/requests/takeunfill.php create mode 100644 sections/requests/takevote.php create mode 100644 sections/rules/chat.php create mode 100644 sections/rules/clients.php create mode 100644 sections/rules/collages.php create mode 100644 sections/rules/index.php create mode 100644 sections/rules/jump.php create mode 100644 sections/rules/ratio.php create mode 100644 sections/rules/requests.php create mode 100644 sections/rules/rules.php create mode 100644 sections/rules/tag.php create mode 100644 sections/rules/upload.php create mode 100644 sections/schedule/index.php create mode 100644 sections/staff/functions.php create mode 100644 sections/staff/index.php create mode 100644 sections/staffblog/index.php create mode 100644 sections/staffpm/ajax_delete_response.php create mode 100644 sections/staffpm/ajax_edit_response.php create mode 100644 sections/staffpm/ajax_get_response.php create mode 100644 sections/staffpm/ajax_preview_response.php create mode 100644 sections/staffpm/assign.php create mode 100644 sections/staffpm/common_responses.php create mode 100644 sections/staffpm/functions.php create mode 100644 sections/staffpm/index.php create mode 100644 sections/staffpm/makedonor.php create mode 100644 sections/staffpm/multiresolve.php create mode 100644 sections/staffpm/resolve.php create mode 100644 sections/staffpm/staff_inbox.php create mode 100644 sections/staffpm/takepost.php create mode 100644 sections/staffpm/unresolve.php create mode 100644 sections/staffpm/user_inbox.php create mode 100644 sections/staffpm/viewconv.php create mode 100644 sections/stats/index.php create mode 100644 sections/stats/torrents.php create mode 100644 sections/stats/users.php create mode 100644 sections/tools/data/bitcoin_balance.php create mode 100644 sections/tools/data/browser_support.php create mode 100644 sections/tools/data/database_specifics.php create mode 100644 sections/tools/data/donation_log.php create mode 100644 sections/tools/data/economic_stats.php create mode 100644 sections/tools/data/invite_pool.php create mode 100644 sections/tools/data/opcode_stats.php create mode 100644 sections/tools/data/registration_log.php create mode 100644 sections/tools/data/service_stats.php create mode 100644 sections/tools/data/special_users.php create mode 100644 sections/tools/data/torrent_stats.php create mode 100644 sections/tools/data/upscale_pool.php create mode 100644 sections/tools/data/user_flow.php create mode 100644 sections/tools/index.php create mode 100644 sections/tools/managers/bans.php create mode 100644 sections/tools/managers/dnu_alter.php create mode 100644 sections/tools/managers/dnu_list.php create mode 100644 sections/tools/managers/eb.php create mode 100644 sections/tools/managers/eb_alter.php create mode 100644 sections/tools/managers/forum_alter.php create mode 100644 sections/tools/managers/forum_list.php create mode 100644 sections/tools/managers/login_watch.php create mode 100644 sections/tools/managers/news.php create mode 100644 sections/tools/managers/ocelot.php create mode 100644 sections/tools/managers/official_tags.php create mode 100644 sections/tools/managers/permissions_alter.php create mode 100644 sections/tools/managers/permissions_list.php create mode 100644 sections/tools/managers/recommend_add.php create mode 100644 sections/tools/managers/recommend_alter.php create mode 100644 sections/tools/managers/recommend_list.php create mode 100644 sections/tools/managers/tokens.php create mode 100644 sections/tools/managers/whitelist_alter.php create mode 100644 sections/tools/managers/whitelist_list.php create mode 100644 sections/tools/misc/analysis.php create mode 100644 sections/tools/misc/bugs.php create mode 100644 sections/tools/misc/clear_cache.php create mode 100644 sections/tools/misc/cli_sandbox.php create mode 100644 sections/tools/misc/create_user.php create mode 100644 sections/tools/misc/dupe_ip.php create mode 100644 sections/tools/misc/manipulate_tree.php create mode 100644 sections/tools/misc/mod_sandbox.php create mode 100644 sections/tools/misc/public_sandbox.php create mode 100644 sections/tools/misc/sandbox1.php create mode 100644 sections/tools/misc/sandbox2.php create mode 100644 sections/tools/misc/sandbox3.php create mode 100644 sections/tools/misc/sandbox4.php create mode 100644 sections/tools/misc/sandbox5.php create mode 100644 sections/tools/misc/sandbox6.php create mode 100644 sections/tools/misc/sandbox7.php create mode 100644 sections/tools/misc/sandbox8.php create mode 100644 sections/tools/misc/update_geoip.php create mode 100644 sections/tools/services/get_cc.php create mode 100644 sections/tools/services/get_host.php create mode 100644 sections/tools/tools.php create mode 100644 sections/top10/history.php create mode 100644 sections/top10/index.php create mode 100644 sections/top10/tags.php create mode 100644 sections/top10/torrents.php create mode 100644 sections/top10/users.php create mode 100644 sections/torrents/add_alias.php create mode 100644 sections/torrents/add_tag.php create mode 100644 sections/torrents/browse.php create mode 100644 sections/torrents/browse2.php create mode 100644 sections/torrents/delete.php create mode 100644 sections/torrents/delete_alias.php create mode 100644 sections/torrents/delete_tag.php create mode 100644 sections/torrents/details.php create mode 100644 sections/torrents/download.php create mode 100644 sections/torrents/downloadlist.php create mode 100644 sections/torrents/edit.php create mode 100644 sections/torrents/editgroup.php create mode 100644 sections/torrents/editgroupid.php create mode 100644 sections/torrents/functions.php create mode 100644 sections/torrents/grouplog.php create mode 100644 sections/torrents/history.php create mode 100644 sections/torrents/index.php create mode 100644 sections/torrents/manage_artists.php create mode 100644 sections/torrents/masspm.php create mode 100644 sections/torrents/merge.php create mode 100644 sections/torrents/nonwikiedit.php create mode 100644 sections/torrents/notify.php create mode 100644 sections/torrents/peerlist.php create mode 100644 sections/torrents/redownload.php create mode 100644 sections/torrents/rename.php create mode 100644 sections/torrents/reseed.php create mode 100644 sections/torrents/snatchlist.php create mode 100644 sections/torrents/takedelete.php create mode 100644 sections/torrents/takeedit.php create mode 100644 sections/torrents/takegroupedit.php create mode 100644 sections/torrents/takemasspm.php create mode 100644 sections/torrents/takenewgroup.php create mode 100644 sections/torrents/user.php create mode 100644 sections/torrents/vote_tag.php create mode 100644 sections/upload/index.php create mode 100644 sections/upload/upload.php create mode 100644 sections/upload/upload_handle.php create mode 100644 sections/user/advancedsearch.php create mode 100644 sections/user/connchecker.php create mode 100644 sections/user/deleteinvite.php create mode 100644 sections/user/edit.php create mode 100644 sections/user/index.php create mode 100644 sections/user/invite.php create mode 100644 sections/user/invitetree.php create mode 100644 sections/user/linkedfunctions.php create mode 100644 sections/user/manage_linked.php create mode 100644 sections/user/notify_edit.php create mode 100644 sections/user/notify_handle.php create mode 100644 sections/user/permissions.php create mode 100644 sections/user/search.php create mode 100644 sections/user/sessions.php create mode 100644 sections/user/takeedit.php create mode 100644 sections/user/takeinvite.php create mode 100644 sections/user/takemoderate.php create mode 100644 sections/user/user.php create mode 100644 sections/userhistory/catchup.php create mode 100644 sections/userhistory/catchup_collages.php create mode 100644 sections/userhistory/collage_subscribe.php create mode 100644 sections/userhistory/email_history.php create mode 100644 sections/userhistory/email_history2.php create mode 100644 sections/userhistory/index.php create mode 100644 sections/userhistory/ip_history.php create mode 100644 sections/userhistory/ip_tracker_history.php create mode 100644 sections/userhistory/passkey_history.php create mode 100644 sections/userhistory/password_history.php create mode 100644 sections/userhistory/post_history.php create mode 100644 sections/userhistory/subscribed_collages.php create mode 100644 sections/userhistory/subscriptions.php create mode 100644 sections/userhistory/thread_subscribe.php create mode 100644 sections/userhistory/token_history.php create mode 100644 sections/wiki/add_alias.php create mode 100644 sections/wiki/aliases.php create mode 100644 sections/wiki/article.php create mode 100644 sections/wiki/compare.php create mode 100644 sections/wiki/create.php create mode 100644 sections/wiki/delete.php create mode 100644 sections/wiki/delete_alias.php create mode 100644 sections/wiki/edit.php create mode 100644 sections/wiki/index.php create mode 100644 sections/wiki/link.php create mode 100644 sections/wiki/revert.php create mode 100644 sections/wiki/revisions.php create mode 100644 sections/wiki/search.php create mode 100644 sections/wiki/splash.php create mode 100644 sections/wiki/takecreate.php create mode 100644 sections/wiki/takeedit.php create mode 100644 sections/wiki/takelink.php create mode 100644 sections/wiki/wiki_browse.php create mode 100644 signup.php create mode 100644 sphinx.conf create mode 100644 staff.php create mode 100644 staffblog.php create mode 100644 staffpm.php create mode 100644 static/blank.gif create mode 100644 static/common/avatars/blank.gif create mode 100644 static/common/avatars/default.png create mode 100644 static/common/caticons/apps.png create mode 100644 static/common/caticons/audiobook.png create mode 100644 static/common/caticons/comedy.png create mode 100644 static/common/caticons/comics.png create mode 100644 static/common/caticons/ebook.png create mode 100644 static/common/caticons/elearning.png create mode 100644 static/common/caticons/music.png create mode 100644 static/common/logo.png create mode 100644 static/common/noartwork/apps.png create mode 100644 static/common/noartwork/audiobook.png create mode 100644 static/common/noartwork/comedy.png create mode 100644 static/common/noartwork/comics.png create mode 100644 static/common/noartwork/ebook.png create mode 100644 static/common/noartwork/elearning.png create mode 100644 static/common/noartwork/music.png create mode 100644 static/common/oink.png create mode 100644 static/common/perfect.gif create mode 100644 static/common/smileys/angry.gif create mode 100644 static/common/smileys/biggrin.gif create mode 100644 static/common/smileys/blank.gif create mode 100644 static/common/smileys/blush.gif create mode 100644 static/common/smileys/cool.gif create mode 100644 static/common/smileys/creepy.gif create mode 100644 static/common/smileys/crying.gif create mode 100644 static/common/smileys/eyesright.gif create mode 100644 static/common/smileys/frown.gif create mode 100644 static/common/smileys/heart.gif create mode 100644 static/common/smileys/hmm.gif create mode 100644 static/common/smileys/ilu.gif create mode 100644 static/common/smileys/laughing.gif create mode 100644 static/common/smileys/loveflac.gif create mode 100644 static/common/smileys/ninja.gif create mode 100644 static/common/smileys/no.gif create mode 100644 static/common/smileys/nod.gif create mode 100644 static/common/smileys/ohnoes.gif create mode 100644 static/common/smileys/ohshit.gif create mode 100644 static/common/smileys/omg.gif create mode 100644 static/common/smileys/paddle.gif create mode 100644 static/common/smileys/sad.gif create mode 100644 static/common/smileys/shifty.gif create mode 100644 static/common/smileys/sick.gif create mode 100644 static/common/smileys/smile.gif create mode 100644 static/common/smileys/sorry.gif create mode 100644 static/common/smileys/thanks.gif create mode 100644 static/common/smileys/tongue.gif create mode 100644 static/common/smileys/wave.gif create mode 100644 static/common/smileys/wink.gif create mode 100644 static/common/smileys/worried.gif create mode 100644 static/common/smileys/wtf.gif create mode 100644 static/common/smileys/wub.gif create mode 100644 static/common/symbols/disabled.png create mode 100644 static/common/symbols/donor.png create mode 100644 static/common/symbols/first-line-support.png create mode 100644 static/common/symbols/read.png create mode 100644 static/common/symbols/readlocked.png create mode 100644 static/common/symbols/readlockedsticky.png create mode 100644 static/common/symbols/readsticky.png create mode 100644 static/common/symbols/rss.png create mode 100644 static/common/symbols/unread.png create mode 100644 static/common/symbols/unreadlocked.png create mode 100644 static/common/symbols/unreadlockedsticky.png create mode 100644 static/common/symbols/unreadsticky.png create mode 100644 static/common/symbols/uploader.png create mode 100644 static/common/symbols/warned.png create mode 100644 static/common/symbols/watched.png create mode 100644 static/common/trumpchart.png create mode 100644 static/functions/artists.js create mode 100644 static/functions/autocomplete.js create mode 100644 static/functions/bbcode.js create mode 100644 static/functions/browse.js create mode 100644 static/functions/captcha.js create mode 100644 static/functions/class_ajax.js create mode 100644 static/functions/class_cookie.js create mode 100644 static/functions/class_countdown.js create mode 100644 static/functions/class_hotkey.js create mode 100644 static/functions/class_storage.js create mode 100644 static/functions/collage.js create mode 100644 static/functions/comments.js create mode 100644 static/functions/delays.js create mode 100644 static/functions/global.js create mode 100644 static/functions/inbox.js create mode 100644 static/functions/iphone.js create mode 100644 static/functions/jquery.js create mode 100644 static/functions/notifications.js create mode 100644 static/functions/reportsv2.js create mode 100644 static/functions/requests.js create mode 100644 static/functions/rippy.js create mode 100644 static/functions/script_start.js create mode 100644 static/functions/sizzle.js create mode 100644 static/functions/staffpm.js create mode 100644 static/functions/subscriptions.js create mode 100644 static/functions/torrent.js create mode 100644 static/functions/transitions.js create mode 100644 static/functions/upload.js create mode 100644 static/functions/user.js create mode 100644 static/functions/validate.js create mode 100644 static/functions/wiki.js create mode 100644 static/irc/IRCApplet.class create mode 100644 static/irc/english.lng create mode 100644 static/irc/irc.jar create mode 100644 static/irc/sbox-english.lng create mode 100644 static/irc/sbox.jar create mode 100644 static/styles/anorex/images/apps.png create mode 100644 static/styles/anorex/images/audiobook.png create mode 100644 static/styles/anorex/images/bar.gif create mode 100644 static/styles/anorex/images/bar_left.gif create mode 100644 static/styles/anorex/images/bar_right.gif create mode 100644 static/styles/anorex/images/comedy.png create mode 100644 static/styles/anorex/images/comics.png create mode 100644 static/styles/anorex/images/ebook.png create mode 100644 static/styles/anorex/images/elearning.png create mode 100644 static/styles/anorex/images/go_last_read.png create mode 100644 static/styles/anorex/images/hide.png create mode 100644 static/styles/anorex/images/leechers.png create mode 100644 static/styles/anorex/images/locked_read.png create mode 100644 static/styles/anorex/images/locked_sticky_read.png create mode 100644 static/styles/anorex/images/locked_sticky_unread.png create mode 100644 static/styles/anorex/images/locked_unread.png create mode 100644 static/styles/anorex/images/logo.png create mode 100644 static/styles/anorex/images/music.png create mode 100644 static/styles/anorex/images/read.png create mode 100644 static/styles/anorex/images/seeders.png create mode 100644 static/styles/anorex/images/show.png create mode 100644 static/styles/anorex/images/snatched.png create mode 100644 static/styles/anorex/images/sticky_read.png create mode 100644 static/styles/anorex/images/sticky_unread.png create mode 100644 static/styles/anorex/images/unread.png create mode 100644 static/styles/anorex/images/woodbg.png create mode 100644 static/styles/anorex/images/woodfoot.png create mode 100644 static/styles/anorex/images/woodhead.png create mode 100644 static/styles/anorex/images/woodnav.png create mode 100644 static/styles/anorex/images/woodnavcenter.png create mode 100644 static/styles/anorex/style.css create mode 100644 static/styles/arrow.png create mode 100644 static/styles/celebrate/banner.gif create mode 100644 static/styles/celebrate/celebrate.css create mode 100644 static/styles/celebrate/celebratetheme.css create mode 100644 static/styles/celebrate/fireworks.jpg create mode 100644 static/styles/celebrate/images/Akzidenz.otf create mode 100644 static/styles/celebrate/images/Anonymous.ttf create mode 100644 static/styles/celebrate/images/Avant.otf create mode 100644 static/styles/celebrate/images/CorpidOffice.ttf create mode 100644 static/styles/celebrate/images/Officina.otf create mode 100644 static/styles/celebrate/images/alert-overlay.png create mode 100644 static/styles/celebrate/images/bg_footer.png create mode 100644 static/styles/celebrate/images/bg_header.png create mode 100644 static/styles/celebrate/images/bg_inputs.png create mode 100644 static/styles/celebrate/images/bg_menu.png create mode 100644 static/styles/celebrate/images/body.jpg create mode 100644 static/styles/celebrate/images/content.png create mode 100644 static/styles/celebrate/images/content_light.png create mode 100644 static/styles/celebrate/images/external.png create mode 100644 static/styles/celebrate/images/gazelle.png create mode 100644 static/styles/celebrate/images/go_last_read.png create mode 100644 static/styles/celebrate/images/hide.png create mode 100644 static/styles/celebrate/images/leechers.png create mode 100644 static/styles/celebrate/images/load.gif create mode 100644 static/styles/celebrate/images/locked_read.png create mode 100644 static/styles/celebrate/images/locked_sticky_read.png create mode 100644 static/styles/celebrate/images/locked_sticky_unread.png create mode 100644 static/styles/celebrate/images/locked_unread.png create mode 100644 static/styles/celebrate/images/logo.png create mode 100644 static/styles/celebrate/images/nav_matrix.png create mode 100644 static/styles/celebrate/images/nav_matrix_extended.png create mode 100644 static/styles/celebrate/images/nu_nav_matrix.png create mode 100644 static/styles/celebrate/images/poll_left.png create mode 100644 static/styles/celebrate/images/poll_middle.png create mode 100644 static/styles/celebrate/images/poll_right.png create mode 100644 static/styles/celebrate/images/read.png create mode 100644 static/styles/celebrate/images/seeders.png create mode 100644 static/styles/celebrate/images/show.png create mode 100644 static/styles/celebrate/images/snatched.png create mode 100644 static/styles/celebrate/images/sticky_read.png create mode 100644 static/styles/celebrate/images/sticky_unread.png create mode 100644 static/styles/celebrate/images/table_header.png create mode 100644 static/styles/celebrate/images/table_header_dark.png create mode 100644 static/styles/celebrate/images/unread.png create mode 100644 static/styles/celebrate/images/wood.jpg create mode 100644 static/styles/celebrate/images/woodlogo.png create mode 100644 static/styles/celebrate/images/wrapper.png create mode 100644 static/styles/dark_ambient/images/apps.png create mode 100644 static/styles/dark_ambient/images/audiobook.png create mode 100644 static/styles/dark_ambient/images/bar2.png create mode 100644 static/styles/dark_ambient/images/bar2_hl.png create mode 100644 static/styles/dark_ambient/images/button.png create mode 100644 static/styles/dark_ambient/images/comedy.png create mode 100644 static/styles/dark_ambient/images/comics.png create mode 100644 static/styles/dark_ambient/images/content_main_x.png create mode 100644 static/styles/dark_ambient/images/content_repeat-x.png create mode 100644 static/styles/dark_ambient/images/ebook.png create mode 100644 static/styles/dark_ambient/images/elearning.png create mode 100644 static/styles/dark_ambient/images/filter.png create mode 100644 static/styles/dark_ambient/images/footer.png create mode 100644 static/styles/dark_ambient/images/forum_post.png create mode 100644 static/styles/dark_ambient/images/go_last_read.png create mode 100644 static/styles/dark_ambient/images/header.png create mode 100644 static/styles/dark_ambient/images/header_logo.png create mode 100644 static/styles/dark_ambient/images/hide.png create mode 100644 static/styles/dark_ambient/images/icons/60s.jpg create mode 100644 static/styles/dark_ambient/images/icons/70s.jpg create mode 100644 static/styles/dark_ambient/images/icons/80s.jpg create mode 100644 static/styles/dark_ambient/images/icons/90s.jpg create mode 100644 static/styles/dark_ambient/images/icons/Thumbs.db create mode 100644 static/styles/dark_ambient/images/icons/alt.jpg create mode 100644 static/styles/dark_ambient/images/icons/ambient.jpg create mode 100644 static/styles/dark_ambient/images/icons/appsmac.jpg create mode 100644 static/styles/dark_ambient/images/icons/appssnd.jpg create mode 100644 static/styles/dark_ambient/images/icons/appswin.jpg create mode 100644 static/styles/dark_ambient/images/icons/audiobooks.jpg create mode 100644 static/styles/dark_ambient/images/icons/bluegrass.jpg create mode 100644 static/styles/dark_ambient/images/icons/blues.jpg create mode 100644 static/styles/dark_ambient/images/icons/breaks.jpg create mode 100644 static/styles/dark_ambient/images/icons/classical.jpg create mode 100644 static/styles/dark_ambient/images/icons/comedy.jpg create mode 100644 static/styles/dark_ambient/images/icons/comics.jpg create mode 100644 static/styles/dark_ambient/images/icons/country.jpg create mode 100644 static/styles/dark_ambient/images/icons/dance.jpg create mode 100644 static/styles/dark_ambient/images/icons/disco.jpg create mode 100644 static/styles/dark_ambient/images/icons/dnb.jpg create mode 100644 static/styles/dark_ambient/images/icons/ebooksfic.jpg create mode 100644 static/styles/dark_ambient/images/icons/ebooksnonfic.jpg create mode 100644 static/styles/dark_ambient/images/icons/electronic.jpg create mode 100644 static/styles/dark_ambient/images/icons/emo.jpg create mode 100644 static/styles/dark_ambient/images/icons/experimental.jpg create mode 100644 static/styles/dark_ambient/images/icons/folk.jpg create mode 100644 static/styles/dark_ambient/images/icons/funk.jpg create mode 100644 static/styles/dark_ambient/images/icons/garage.jpg create mode 100644 static/styles/dark_ambient/images/icons/generic.png create mode 100644 static/styles/dark_ambient/images/icons/grunge.jpg create mode 100644 static/styles/dark_ambient/images/icons/hardcore.jpg create mode 100644 static/styles/dark_ambient/images/icons/hardcoredance.jpg create mode 100644 static/styles/dark_ambient/images/icons/hiphop.jpg create mode 100644 static/styles/dark_ambient/images/icons/house.jpg create mode 100644 static/styles/dark_ambient/images/icons/idm.jpg create mode 100644 static/styles/dark_ambient/images/icons/indie.jpg create mode 100644 static/styles/dark_ambient/images/icons/industrial.jpg create mode 100644 static/styles/dark_ambient/images/icons/jazz.jpg create mode 100644 static/styles/dark_ambient/images/icons/jpop.jpg create mode 100644 static/styles/dark_ambient/images/icons/locked_read.png create mode 100644 static/styles/dark_ambient/images/icons/locked_sticky_read.png create mode 100644 static/styles/dark_ambient/images/icons/locked_sticky_unread.png create mode 100644 static/styles/dark_ambient/images/icons/locked_unread.png create mode 100644 static/styles/dark_ambient/images/icons/metal.jpg create mode 100644 static/styles/dark_ambient/images/icons/newage.jpg create mode 100644 static/styles/dark_ambient/images/icons/ost.jpg create mode 100644 static/styles/dark_ambient/images/icons/pop.jpg create mode 100644 static/styles/dark_ambient/images/icons/postrock.jpg create mode 100644 static/styles/dark_ambient/images/icons/progrock.jpg create mode 100644 static/styles/dark_ambient/images/icons/psychedelic.jpg create mode 100644 static/styles/dark_ambient/images/icons/psytrance.jpg create mode 100644 static/styles/dark_ambient/images/icons/punk.jpg create mode 100644 static/styles/dark_ambient/images/icons/read.png create mode 100644 static/styles/dark_ambient/images/icons/reggae.jpg create mode 100644 static/styles/dark_ambient/images/icons/rnb.jpg create mode 100644 static/styles/dark_ambient/images/icons/rock.jpg create mode 100644 static/styles/dark_ambient/images/icons/ska.jpg create mode 100644 static/styles/dark_ambient/images/icons/soul.jpg create mode 100644 static/styles/dark_ambient/images/icons/sticky_read.png create mode 100644 static/styles/dark_ambient/images/icons/sticky_unread.png create mode 100644 static/styles/dark_ambient/images/icons/techno.jpg create mode 100644 static/styles/dark_ambient/images/icons/trance.jpg create mode 100644 static/styles/dark_ambient/images/icons/triphop.jpg create mode 100644 static/styles/dark_ambient/images/icons/ukgarage.jpg create mode 100644 static/styles/dark_ambient/images/icons/unread.png create mode 100644 static/styles/dark_ambient/images/icons/world.jpg create mode 100644 static/styles/dark_ambient/images/inputbg.png create mode 100644 static/styles/dark_ambient/images/leechers.png create mode 100644 static/styles/dark_ambient/images/music.png create mode 100644 static/styles/dark_ambient/images/poll_left.png create mode 100644 static/styles/dark_ambient/images/poll_middle.png create mode 100644 static/styles/dark_ambient/images/poll_right.png create mode 100644 static/styles/dark_ambient/images/searchbox.png create mode 100644 static/styles/dark_ambient/images/seeders.png create mode 100644 static/styles/dark_ambient/images/show.png create mode 100644 static/styles/dark_ambient/images/snatched.png create mode 100644 static/styles/dark_ambient/images/tags.png create mode 100644 static/styles/dark_ambient/images/what_logo.png create mode 100644 static/styles/dark_ambient/images/wrapper.png create mode 100644 static/styles/dark_ambient/style.css create mode 100644 static/styles/global.css create mode 100644 static/styles/gtfo_spaceship/fonts/aller_rg-webfont.ttf create mode 100644 static/styles/gtfo_spaceship/fonts/allerdisplay-webfont.ttf create mode 100644 static/styles/gtfo_spaceship/images/chevroni-axxion-down.png create mode 100644 static/styles/gtfo_spaceship/images/chevroni-axxion-right.png create mode 100644 static/styles/gtfo_spaceship/images/chevroni-axxion.png create mode 100644 static/styles/gtfo_spaceship/images/doppleganger-management.png create mode 100644 static/styles/gtfo_spaceship/images/glyphicons_067_bookmark.png create mode 100644 static/styles/gtfo_spaceship/images/glyphicons_089_logbook.png create mode 100644 static/styles/gtfo_spaceship/images/glyphicons_162_right_arrow.png create mode 100644 static/styles/gtfo_spaceship/images/go_last_read.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys-A.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys-F.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys-L.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys-R.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys-T.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys-U.png create mode 100644 static/styles/gtfo_spaceship/images/hey-you-guys.png create mode 100644 static/styles/gtfo_spaceship/images/icanhaztm.png create mode 100644 static/styles/gtfo_spaceship/images/large_read_glyphicons_040_conversation.png create mode 100644 static/styles/gtfo_spaceship/images/large_unread_glyphicons_040_conversation.png create mode 100644 static/styles/gtfo_spaceship/images/large_unread_glyphicons_040_conversation.png.1 create mode 100644 static/styles/gtfo_spaceship/images/leechers.png create mode 100644 static/styles/gtfo_spaceship/images/much-luv.png create mode 100644 static/styles/gtfo_spaceship/images/my-dictator-in-a-box-hover.png create mode 100644 static/styles/gtfo_spaceship/images/my-dictator-in-a-box.png create mode 100644 static/styles/gtfo_spaceship/images/overlay-button.png create mode 100644 static/styles/gtfo_spaceship/images/poll-bg.png create mode 100644 static/styles/gtfo_spaceship/images/poll-end.png create mode 100644 static/styles/gtfo_spaceship/images/poll-wide-bg.png create mode 100644 static/styles/gtfo_spaceship/images/prong-dawg.png create mode 100644 static/styles/gtfo_spaceship/images/purple-jizz.jpg create mode 100644 static/styles/gtfo_spaceship/images/quote.png create mode 100644 static/styles/gtfo_spaceship/images/read-and-obey-or-else.png create mode 100644 static/styles/gtfo_spaceship/images/seeders.png create mode 100644 static/styles/gtfo_spaceship/images/small_locked_read_glyphicons_070_link.png create mode 100644 static/styles/gtfo_spaceship/images/small_locked_unread_glyphicons_070_link.png create mode 100644 static/styles/gtfo_spaceship/images/small_read_glyphicons_040_conversation.png create mode 100644 static/styles/gtfo_spaceship/images/small_sticky_read_glyphicons_033_star.png create mode 100644 static/styles/gtfo_spaceship/images/small_sticky_unread_glyphicons_033_star.png create mode 100644 static/styles/gtfo_spaceship/images/small_unread_glyphicons_040_conversation.png create mode 100644 static/styles/gtfo_spaceship/images/snatched.png create mode 100644 static/styles/gtfo_spaceship/images/squizzare.png create mode 100644 static/styles/gtfo_spaceship/images/vroooooom-done.png create mode 100644 static/styles/gtfo_spaceship/images/who-cd.png create mode 100644 static/styles/gtfo_spaceship/images/yo-dawg-i-heard-you-like-cds.png create mode 100644 static/styles/gtfo_spaceship/images/z0mg-look.png create mode 100644 static/styles/gtfo_spaceship/style.css create mode 100644 static/styles/hydro/images/apps.png create mode 100644 static/styles/hydro/images/audiobook.png create mode 100644 static/styles/hydro/images/bar.gif create mode 100644 static/styles/hydro/images/bar_left.gif create mode 100644 static/styles/hydro/images/bar_right.gif create mode 100644 static/styles/hydro/images/bars.gif create mode 100644 static/styles/hydro/images/close.png create mode 100644 static/styles/hydro/images/colhead-grad.gif create mode 100644 static/styles/hydro/images/comedy.png create mode 100644 static/styles/hydro/images/comics.png create mode 100644 static/styles/hydro/images/ebook.png create mode 100644 static/styles/hydro/images/elearning.png create mode 100644 static/styles/hydro/images/go_last_read.png create mode 100644 static/styles/hydro/images/header.png create mode 100644 static/styles/hydro/images/hide.png create mode 100644 static/styles/hydro/images/leechers.png create mode 100644 static/styles/hydro/images/locked_read.png create mode 100644 static/styles/hydro/images/locked_sticky_read.png create mode 100644 static/styles/hydro/images/locked_sticky_unread.png create mode 100644 static/styles/hydro/images/locked_unread.png create mode 100644 static/styles/hydro/images/logo.png create mode 100644 static/styles/hydro/images/music.png create mode 100644 static/styles/hydro/images/open.png create mode 100644 static/styles/hydro/images/read.png create mode 100644 static/styles/hydro/images/seeders.png create mode 100644 static/styles/hydro/images/show.png create mode 100644 static/styles/hydro/images/snatched.png create mode 100644 static/styles/hydro/images/sticky_read.png create mode 100644 static/styles/hydro/images/sticky_unread.png create mode 100644 static/styles/hydro/images/unread.png create mode 100644 static/styles/hydro/style.css create mode 100644 static/styles/kuro/images/apps.png create mode 100644 static/styles/kuro/images/audiobook.png create mode 100644 static/styles/kuro/images/bar.gif create mode 100644 static/styles/kuro/images/bar_left.gif create mode 100644 static/styles/kuro/images/bar_right.gif create mode 100644 static/styles/kuro/images/comedy.png create mode 100644 static/styles/kuro/images/comics.png create mode 100644 static/styles/kuro/images/ebook.png create mode 100644 static/styles/kuro/images/elearning.png create mode 100644 static/styles/kuro/images/go_last_read.png create mode 100644 static/styles/kuro/images/hide.png create mode 100644 static/styles/kuro/images/leechers.png create mode 100644 static/styles/kuro/images/locked_read.png create mode 100644 static/styles/kuro/images/locked_sticky.png create mode 100644 static/styles/kuro/images/locked_sticky_read.png create mode 100644 static/styles/kuro/images/locked_sticky_unread.png create mode 100644 static/styles/kuro/images/locked_unread.png create mode 100644 static/styles/kuro/images/logo.png create mode 100644 static/styles/kuro/images/music.png create mode 100644 static/styles/kuro/images/read.png create mode 100644 static/styles/kuro/images/seeders.png create mode 100644 static/styles/kuro/images/show.png create mode 100644 static/styles/kuro/images/snatched.png create mode 100644 static/styles/kuro/images/sticky.png create mode 100644 static/styles/kuro/images/sticky_read.png create mode 100644 static/styles/kuro/images/sticky_unread.png create mode 100644 static/styles/kuro/images/unread.png create mode 100644 static/styles/kuro/style.css create mode 100644 static/styles/layer_cake/images/apps.png create mode 100644 static/styles/layer_cake/images/audiobook.png create mode 100644 static/styles/layer_cake/images/auto.png create mode 100644 static/styles/layer_cake/images/bar.gif create mode 100644 static/styles/layer_cake/images/bar_left.gif create mode 100644 static/styles/layer_cake/images/bar_right.gif create mode 100644 static/styles/layer_cake/images/comedy.png create mode 100644 static/styles/layer_cake/images/comics.png create mode 100644 static/styles/layer_cake/images/ebook.png create mode 100644 static/styles/layer_cake/images/elearning.png create mode 100644 static/styles/layer_cake/images/go_last_read.png create mode 100644 static/styles/layer_cake/images/grayarrow_close.png create mode 100644 static/styles/layer_cake/images/grayarrow_open.png create mode 100644 static/styles/layer_cake/images/headerbg.png create mode 100644 static/styles/layer_cake/images/hide.png create mode 100644 static/styles/layer_cake/images/leechers.png create mode 100644 static/styles/layer_cake/images/locked_read.png create mode 100644 static/styles/layer_cake/images/locked_sticky_read.png create mode 100644 static/styles/layer_cake/images/locked_sticky_unread.png create mode 100644 static/styles/layer_cake/images/locked_unread.png create mode 100644 static/styles/layer_cake/images/logo.png create mode 100644 static/styles/layer_cake/images/messages.gif create mode 100644 static/styles/layer_cake/images/music.png create mode 100644 static/styles/layer_cake/images/newmessages.gif create mode 100644 static/styles/layer_cake/images/read.png create mode 100644 static/styles/layer_cake/images/seeders.png create mode 100644 static/styles/layer_cake/images/show.png create mode 100644 static/styles/layer_cake/images/snatched.png create mode 100644 static/styles/layer_cake/images/sticky_read.png create mode 100644 static/styles/layer_cake/images/sticky_unread.png create mode 100644 static/styles/layer_cake/images/unread.png create mode 100644 static/styles/layer_cake/style.css create mode 100644 static/styles/layer_cake/style2.css create mode 100644 static/styles/log.css create mode 100644 static/styles/minimal/images/balloon-unread.png create mode 100644 static/styles/minimal/images/balloon.png create mode 100644 static/styles/minimal/images/bg.png create mode 100644 static/styles/minimal/images/blockquote.png create mode 100644 static/styles/minimal/images/go_last_read.png create mode 100644 static/styles/minimal/images/icons/apps.png create mode 100644 static/styles/minimal/images/icons/audiobook.png create mode 100644 static/styles/minimal/images/icons/comedy.png create mode 100644 static/styles/minimal/images/icons/comics.png create mode 100644 static/styles/minimal/images/icons/ebook.png create mode 100644 static/styles/minimal/images/icons/elearning.png create mode 100644 static/styles/minimal/images/icons/music.png create mode 100644 static/styles/minimal/images/leechers.png create mode 100644 static/styles/minimal/images/lock-sticky-unread.png create mode 100644 static/styles/minimal/images/lock-sticky.png create mode 100644 static/styles/minimal/images/lock-unread.png create mode 100644 static/styles/minimal/images/lock.png create mode 100644 static/styles/minimal/images/logo.png create mode 100644 static/styles/minimal/images/poll_left.png create mode 100644 static/styles/minimal/images/poll_middle.png create mode 100644 static/styles/minimal/images/poll_right.png create mode 100644 static/styles/minimal/images/seeders.png create mode 100644 static/styles/minimal/images/snatched.png create mode 100644 static/styles/minimal/images/sprite.png create mode 100644 static/styles/minimal/images/sticky-unread.png create mode 100644 static/styles/minimal/images/sticky.png create mode 100644 static/styles/minimal/images/unread.png create mode 100644 static/styles/minimal/style.css create mode 100644 static/styles/minimal/style2.css create mode 100644 static/styles/minimal_mod_alt.css create mode 100644 static/styles/mono/icons/applications.png create mode 100644 static/styles/mono/icons/audiobooks.png create mode 100644 static/styles/mono/icons/comedy.png create mode 100644 static/styles/mono/icons/comics.png create mode 100644 static/styles/mono/icons/ebooks.png create mode 100644 static/styles/mono/icons/elearning.png create mode 100644 static/styles/mono/icons/goto.png create mode 100644 static/styles/mono/icons/music.png create mode 100644 static/styles/mono/icons/quote-mark.png create mode 100644 static/styles/mono/icons/read-locked.png create mode 100644 static/styles/mono/icons/read.png create mode 100644 static/styles/mono/icons/show-hide.png create mode 100644 static/styles/mono/icons/sticky-read-locked.png create mode 100644 static/styles/mono/icons/sticky-read.png create mode 100644 static/styles/mono/icons/sticky-unread-locked.png create mode 100644 static/styles/mono/icons/sticky-unread.png create mode 100644 static/styles/mono/icons/unread.png create mode 100644 static/styles/mono/images/leechers.png create mode 100644 static/styles/mono/images/seeders.png create mode 100644 static/styles/mono/images/snatched.png create mode 100644 static/styles/mono/style.css create mode 100644 static/styles/postmod.zip create mode 100644 static/styles/postmod/images/Akzidenz.otf create mode 100644 static/styles/postmod/images/Anonymous.ttf create mode 100644 static/styles/postmod/images/Avant.otf create mode 100644 static/styles/postmod/images/CorpidOffice.ttf create mode 100644 static/styles/postmod/images/Officina.otf create mode 100644 static/styles/postmod/images/alert-overlay.png create mode 100644 static/styles/postmod/images/bg_footer.png create mode 100644 static/styles/postmod/images/bg_header.png create mode 100644 static/styles/postmod/images/bg_inputs.png create mode 100644 static/styles/postmod/images/bg_menu.png create mode 100644 static/styles/postmod/images/body.jpg create mode 100644 static/styles/postmod/images/content.png create mode 100644 static/styles/postmod/images/content_light.png create mode 100644 static/styles/postmod/images/external.png create mode 100644 static/styles/postmod/images/gazelle.png create mode 100644 static/styles/postmod/images/go_last_read.png create mode 100644 static/styles/postmod/images/hide.png create mode 100644 static/styles/postmod/images/leechers.png create mode 100644 static/styles/postmod/images/load.gif create mode 100644 static/styles/postmod/images/locked_read.png create mode 100644 static/styles/postmod/images/locked_sticky_read.png create mode 100644 static/styles/postmod/images/locked_sticky_unread.png create mode 100644 static/styles/postmod/images/locked_unread.png create mode 100644 static/styles/postmod/images/logo.png create mode 100644 static/styles/postmod/images/nav_matrix.png create mode 100644 static/styles/postmod/images/nav_matrix_extended.png create mode 100644 static/styles/postmod/images/nu_nav_matrix.png create mode 100644 static/styles/postmod/images/poll_left.png create mode 100644 static/styles/postmod/images/poll_middle.png create mode 100644 static/styles/postmod/images/poll_right.png create mode 100644 static/styles/postmod/images/read.png create mode 100644 static/styles/postmod/images/seeders.png create mode 100644 static/styles/postmod/images/show.png create mode 100644 static/styles/postmod/images/snatched.png create mode 100644 static/styles/postmod/images/sticky_read.png create mode 100644 static/styles/postmod/images/sticky_unread.png create mode 100644 static/styles/postmod/images/table_header.png create mode 100644 static/styles/postmod/images/table_header_dark.png create mode 100644 static/styles/postmod/images/unread.png create mode 100644 static/styles/postmod/images/wood.jpg create mode 100644 static/styles/postmod/images/woodlogo.png create mode 100644 static/styles/postmod/images/wrapper.png create mode 100644 static/styles/postmod/map.html create mode 100644 static/styles/postmod/style.css create mode 100644 static/styles/proton/images/apps.png create mode 100644 static/styles/proton/images/audiobook.png create mode 100644 static/styles/proton/images/category/apps.png create mode 100644 static/styles/proton/images/category/audiobook.png create mode 100644 static/styles/proton/images/category/comedy.png create mode 100644 static/styles/proton/images/category/comics.png create mode 100644 static/styles/proton/images/category/ebook.png create mode 100644 static/styles/proton/images/category/elearning.png create mode 100644 static/styles/proton/images/category/music.png create mode 100644 static/styles/proton/images/closebox.png create mode 100644 static/styles/proton/images/comedy.png create mode 100644 static/styles/proton/images/comics.png create mode 100644 static/styles/proton/images/convo.png create mode 100644 static/styles/proton/images/discogbglight.png create mode 100644 static/styles/proton/images/discogbglightshadow.png create mode 100644 static/styles/proton/images/dl.png create mode 100644 static/styles/proton/images/download.png create mode 100644 static/styles/proton/images/download_bottom.png create mode 100644 static/styles/proton/images/ebook.png create mode 100644 static/styles/proton/images/elearning.png create mode 100644 static/styles/proton/images/filter.png create mode 100644 static/styles/proton/images/footer_bg.png create mode 100644 static/styles/proton/images/forum_postbg.png create mode 100644 static/styles/proton/images/forum_postbgspeech1.png create mode 100644 static/styles/proton/images/forum_postbgspeech2.png create mode 100644 static/styles/proton/images/forum_postbgspeech3.png create mode 100644 static/styles/proton/images/forum_postbodybg.png create mode 100644 static/styles/proton/images/forums/go_last_read.png create mode 100644 static/styles/proton/images/forums/locked_read.gif create mode 100644 static/styles/proton/images/forums/locked_sticky_read.gif create mode 100644 static/styles/proton/images/forums/locked_sticky_unread.gif create mode 100644 static/styles/proton/images/forums/locked_unread.gif create mode 100644 static/styles/proton/images/forums/read.gif create mode 100644 static/styles/proton/images/forums/sticky_read.gif create mode 100644 static/styles/proton/images/forums/sticky_unread.gif create mode 100644 static/styles/proton/images/forums/unread.gif create mode 100644 static/styles/proton/images/go_last_read.png create mode 100644 static/styles/proton/images/inputbg.png create mode 100644 static/styles/proton/images/leechers.png create mode 100644 static/styles/proton/images/locked.png create mode 100644 static/styles/proton/images/locked_read.gif create mode 100644 static/styles/proton/images/locked_read.png create mode 100644 static/styles/proton/images/locked_sticky.png create mode 100644 static/styles/proton/images/locked_sticky_read.gif create mode 100644 static/styles/proton/images/locked_sticky_read.png create mode 100644 static/styles/proton/images/locked_sticky_unread.gif create mode 100644 static/styles/proton/images/locked_sticky_unread.png create mode 100644 static/styles/proton/images/locked_unread.gif create mode 100644 static/styles/proton/images/locked_unread.png create mode 100644 static/styles/proton/images/music.png create mode 100644 static/styles/proton/images/poll_left.png create mode 100644 static/styles/proton/images/poll_middle.png create mode 100644 static/styles/proton/images/poll_right.png create mode 100644 static/styles/proton/images/proton18052010.zip create mode 100644 static/styles/proton/images/quote_bg.png create mode 100644 static/styles/proton/images/read.gif create mode 100644 static/styles/proton/images/read.png create mode 100644 static/styles/proton/images/searchbox.png create mode 100644 static/styles/proton/images/seeders.png create mode 100644 static/styles/proton/images/snatched.png create mode 100644 static/styles/proton/images/sticky.png create mode 100644 static/styles/proton/images/sticky_read.gif create mode 100644 static/styles/proton/images/sticky_read.png create mode 100644 static/styles/proton/images/sticky_unread.gif create mode 100644 static/styles/proton/images/sticky_unread.png create mode 100644 static/styles/proton/images/tags.png create mode 100644 static/styles/proton/images/unread.gif create mode 100644 static/styles/proton/images/unread.png create mode 100644 static/styles/proton/images/what_bg.gif create mode 100644 static/styles/proton/images/what_bg.jpg create mode 100644 static/styles/proton/images/what_head3.jpg create mode 100644 static/styles/proton/images/what_head3_shadow.jpg create mode 100644 static/styles/proton/images/what_hide.gif create mode 100644 static/styles/proton/images/what_hide.png create mode 100644 static/styles/proton/images/what_logo.png create mode 100644 static/styles/proton/images/what_show.gif create mode 100644 static/styles/proton/images/what_show.png create mode 100644 static/styles/proton/style.css create mode 100644 static/styles/public/images/bg.png create mode 100644 static/styles/public/images/footer.png create mode 100644 static/styles/public/images/logo.png create mode 100644 static/styles/public/images/sprite.png create mode 100644 static/styles/public/images/watermark.png create mode 100644 static/styles/public/style.css create mode 100644 static/styles/shiro/images/apps.png create mode 100644 static/styles/shiro/images/audiobook.png create mode 100644 static/styles/shiro/images/auto.png create mode 100644 static/styles/shiro/images/bar.gif create mode 100644 static/styles/shiro/images/bar_left.gif create mode 100644 static/styles/shiro/images/bar_right.gif create mode 100644 static/styles/shiro/images/close.png create mode 100644 static/styles/shiro/images/comedy.png create mode 100644 static/styles/shiro/images/comics.png create mode 100644 static/styles/shiro/images/ebook.png create mode 100644 static/styles/shiro/images/elearning.png create mode 100644 static/styles/shiro/images/go_last_read.png create mode 100644 static/styles/shiro/images/hide.png create mode 100644 static/styles/shiro/images/leechers.png create mode 100644 static/styles/shiro/images/locked_read.png create mode 100644 static/styles/shiro/images/locked_sticky_read.png create mode 100644 static/styles/shiro/images/locked_sticky_unread.png create mode 100644 static/styles/shiro/images/locked_unread.png create mode 100644 static/styles/shiro/images/logo.png create mode 100644 static/styles/shiro/images/music.png create mode 100644 static/styles/shiro/images/open.png create mode 100644 static/styles/shiro/images/read.png create mode 100644 static/styles/shiro/images/seeders.png create mode 100644 static/styles/shiro/images/show.png create mode 100644 static/styles/shiro/images/snatched.png create mode 100644 static/styles/shiro/images/sticky_read.png create mode 100644 static/styles/shiro/images/sticky_unread.png create mode 100644 static/styles/shiro/images/unread.png create mode 100644 static/styles/shiro/style.css create mode 100644 static/styles/whatlove/images/apps.png create mode 100644 static/styles/whatlove/images/audiobook.png create mode 100644 static/styles/whatlove/images/bar.gif create mode 100644 static/styles/whatlove/images/bar_left.gif create mode 100644 static/styles/whatlove/images/bar_right.gif create mode 100644 static/styles/whatlove/images/bg.png create mode 100644 static/styles/whatlove/images/comedy.png create mode 100644 static/styles/whatlove/images/comics.png create mode 100644 static/styles/whatlove/images/ebook.png create mode 100644 static/styles/whatlove/images/elearning.png create mode 100644 static/styles/whatlove/images/go_last_read.png create mode 100644 static/styles/whatlove/images/hide.png create mode 100644 static/styles/whatlove/images/leechers.png create mode 100644 static/styles/whatlove/images/locked_read.png create mode 100644 static/styles/whatlove/images/locked_sticky_read.png create mode 100644 static/styles/whatlove/images/locked_sticky_unread.png create mode 100644 static/styles/whatlove/images/locked_unread.png create mode 100644 static/styles/whatlove/images/logo.png create mode 100644 static/styles/whatlove/images/music.png create mode 100644 static/styles/whatlove/images/read.png create mode 100644 static/styles/whatlove/images/seeders.png create mode 100644 static/styles/whatlove/images/show.png create mode 100644 static/styles/whatlove/images/snatched.png create mode 100644 static/styles/whatlove/images/sticky_read.png create mode 100644 static/styles/whatlove/images/sticky_unread.png create mode 100644 static/styles/whatlove/images/unread.png create mode 100644 static/styles/whatlove/style.css create mode 100644 static/styles/white.cd/images/go_last_read.png create mode 100644 static/styles/white.cd/images/header.png create mode 100644 static/styles/white.cd/images/icons.png create mode 100644 static/styles/white.cd/images/leechers.png create mode 100644 static/styles/white.cd/images/logo.png create mode 100644 static/styles/white.cd/images/seeders.png create mode 100644 static/styles/white.cd/images/snatched.png create mode 100644 static/styles/white.cd/style.css create mode 100644 stats.php create mode 100644 templates/error.tpl create mode 100644 templates/invite.tpl create mode 100644 templates/new_registration.tpl create mode 100644 templates/password_reset.tpl create mode 100644 tools.php create mode 100644 top10.php create mode 100644 torrents.php create mode 100644 upgrade.php create mode 100644 upload.php create mode 100644 user.php create mode 100644 userhistory.php create mode 100644 watchlist.php create mode 100644 whitelist.php create mode 100644 wiki.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..238f7992 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +config.php +release/* +static/similar diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 00000000..8a94261d --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,150 @@ +CHANGELOG +2010-08-28 +-Upgrade Sphinx to 1.10b + +2010-08-25 +-Better handling of special characters in torrent searches +-Improved file name search +-Add negations to request searches + +2010-08-11 +-Fixed long standing IE Bug. Turns out that IE fails to handle unicode data in the Content-disposition header so this value is now urlencoded ensuring compatibility. + +2010-08-10 +-Added check for CustomPerms IP protection on login + +2010-07-30 +-Add collage stats to user profiles + +2010-07-04 +-Updated sphinx.conf + +2010-06-26 +-Fixed IP bans and added to public repo +-Added catch for missing system 'host' command +-Logged in users can't hit register.php +-Fix in URL_REGEX to allow URLs of the form http://foo.com/ + +2010-06-09 +-Delete torrent files when torrent is deleted + +2010-06-04 +-User proper names on bookmark/notify links if a group is already bookmarked or in the notifications + +2010-05-21 +-Sortable invitee list + +2010-05-16 +-Escape tag links on user torrent pages + +2010-05-12 +-Make the "view tags" button change to "hide tags" if tags are shown +-Make editing upload/download amounts work on 32bit systems +-Fix a typo in class_cache, not major +-Add default values to schedule table + +2010-05-09 +-Add catchup link to subscriptions page + +2010-05-05 +-Move $Classes fetching code to somewhere globally accessible so that schedule can fetch it + +2010-05-03 +-Fixed bug in 32bit parser that would allow clients to set private=0 + +2010-05-01 +-Add preview functionality to thread creation page + +2010-04-30 +-Fix various subscription bugs + +2010-04-29 +-Properly update cache and database when a forum post is removed + +2010-04-28 +-Alias IDs now show next to artists in the artist box +-Users with an infinite ratio now get promoted along with those who have a +ratio of 1.05 or higher + +2010-04-26 +-Fixed bug where snatchlists were not visible to other users at paranoia level +1 (should be 2 or higher) + +2010-04-19 +-Add requests to sphinx.conf + +2010-04-18 +-Fix request sorting + +2010-04-15 +-Added clickable staff notes + +2010-04-14 +-Add stylesheet and avatar search to advanced user search + +2010-04-13 +-Require authorization to manually run schedule +-Fix minor bbcode bug which didn't allow question marks in filenames + +2010-04-11 +-Add "visible" checkbox to user profiles. Unticked, this will remove a user from a peer list. +-Add option to disable PM privileges of user + +2010-04-07 +-Fix critical bug where users can view staff forum posts by changing the ID on the reports page + +2010-03-18 +-Clear notifications per torrent or filter + +2010-03-16 +-Notifications groups actually work now +-Post history and subscriptions pages now default to unread posts with collapsed post bodies + +2010-03-14 +-Group notifications by filter + +2010-03-13 +-Added ability to view a user's downloaded torrents as well as snatched + +2010-03-12 +-Thread subscriptions +-Various bugfixes, see resolved gazelle bug forum +-Standardised Email and Image regexes across gazelle + +2010-03-10 +-Completed requestsv2, feel free to use it now + +2010-03-09 +-Add size and files column to notifications page and clone the browse layout +-Don't redirect if ssl url == nonssl url +-Fix some more warnings when calling sphinxapi.php +-Year filter in notifications also checks remaster year + +2010-03-07 +-Change INSERT INTO to REPLACE INTO to avoid errors when updating the sphinx*_delta tables + +2010-03-04 +-Added initial version of requestsv2, will need more updates so not advised to +update yet + +2010-03-02 +-Fixed bug in notifications by tags + +2010-03-01 +-Fixed bug in notifications by release type + +2010-02-28 +-Fixed bug which causes stats to be altered if the tracker updates while someone with stat editing powers moderates a profile +-Fixed artist permission +-Fixed two permission bugs +-Removed references to What.CD in takemoderate.php +-Fixed E_NOTICE with regards to taglist on browse2.php +-Removed geodistribution from stats, fixed stats so they don't whitepage +-Fixed the user geodistribution stats and geoip database updater, and added a function for an unsigned ip2long +-Kill poll manager, it doesn't work anymore - use the forums + -Fix width of poll replies, don't display poll if there aren't any +-Re-add reports folder +-Fixed "database schema" tool +-Fix upscale pool blank message +-Fix number of posts in a forum after a thread has been moved out of it +-Strip out SVN revision echo diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 00000000..a176c22b --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,133 @@ +COPYRIGHTED AND PATENTED PENDING BY WHAT.CD INCORPORATED, DBA/AKA PROJECT +GAZELLE + +END-USER LICENSE AGREEMENT + +The Gazelle Source Code (hereinafter referred to as the Software) is made +publically available free of charge by Project Gazelle (sometimes a trade and +business name for the legally consituted entity known as What.CD Incorporated, +a Panamanian Corporation), copyright and patent pending owner (hereinafter +referred to as the Licensor or Original Licensor) to anyone who wishes to use +and/or share or distribute and/or change or modify it (hereinafter referred to +as either the Licensee and/or End-User) FOR NONCOMMERCIAL PURPOSES ONLY under +the following terms and conditions (hereinafter referred to as the "License"): + +Section 1. You may copy and distribute verbatim copies of the Software's +source code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Software a copy of this License along with the Software. + +Section 2: You may modify or change your copy or copies of the Software or +any portion of it, thus forming a work based on the Software, and copy and +distribute such modifications or work under the terms of Section 1 above, +provided that you also meet all of these conditions: + + 2.1: You must cause the modified files to carry prominent notices stating +that you changed the files and the date of any change. + + 2.2: You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Software or any part thereof, +to be licensed as a whole at no charge to all third parties under the terms of +this License. + +Section 3: You may copy and distribute the Software (or a work based on it, +under the terms of Section 2) in object code or executable form under the +terms of Sections 1 and 2 above provided that you also do one of the +following: + + 3.1: Accompany it with the complete corresponding machine-readable source +code, which must be distributed under the terms of Sections 1 and 2 above on +a medium customarily used for software interchange; or, + + 3.2: Accompany it with a written offer, valid for at least one year, to +give any third party, for a charge no more than your cost of physically +performing source distribution, a complete machine-readable copy of the +corresponding source code, to be distributed under the terms of Sections 1 and +2 above on a medium customarily used for software interchange; or, + + 3.3: Accompany it with the information you received as to the offer to +distribute corresponding source code. (This alternative is allowed only for +noncommercial distribution and only if you received the Software in object +code or executable form with such an offer, in accord with Subsection 3.2 +above.) + +Section 4: You may not copy, modify, sublicense, or distribute the Software +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense or distribute the Software is void, and will +automatically terminate your rights under this License. Parties who have +received copies, or rights, from you under this License, however, will not +have their licenses terminated so long as such parties remain in full +compliance with the terms and conditions of this License. + +Section 5: This License and nothing else grants you permission to use, modify +and/or distribute the Software or its derivative works and only in accordance +with the terms and conditions of this License. Otherwise, use, modification +and/or distribution of this Software is prohibited by international laws and +treaties as regards intellectual property. Therefore, by using, modifying +and/or distributing the Software (or any work based on the Software), you +indicate your acceptance of this License to do so, and all its terms and +conditions for copying, distributing or modifying the software or works based +on it. + +Section 6: Each time you redistribute the Software (or any work based on the +Software), the recipient automatically receives a license from the Original +Licensor to copy, distribute and/or modify the Software subject to these terms +and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. You are not responsible for +enforcing compliance by third parties to this License. + +Section 7: NO WARRANTY + + 7.1: BECAUSE THE SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT/PATENT HOLDERS AND/OR OTHER +PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO +THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE PROGRAM +PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + + 7.2:. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT/PATENT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT +LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED +BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER +SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +Section 8: If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from +the conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Software at all. +For example, if a patent license would not permit royalty-free redistribution +of the Software by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Software. + +Section 9: If any portion or section of this License is held invalid or +unenforceable under any particular circumstance, the balance of this License +and pertinent section is intended to apply and the section as a whole is +intended to apply in other circumstances. + +Section 10: Each version of the Software is given a distinguishing version +number. If the Software specifies a version number of this License which +applies to it and "any later version", you have the option of following the +terms and conditions either of that version or of any later version. If the +Software does not specify a version number of this License, you may choose any +version ever published by the Licensor. + +Section 11: This Software is distributed pursuant to the terms and conditions +of this License and is distributed free of charge FOR NONCOMMERCIAL PURPOSES +ONLY. THE USE, DISTRIBUTION AND/OR MODIFICATION OF THIS SOFTWARE FOR +COMMERCIAL PURPOSES IS EXPRESSLY PROHIBITED BY INTERNATIONAL LAWS AND TREATIES +AS REGARDS INTELLECTUAL PROPERTY. + diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 00000000..ef75c920 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,30 @@ +INSTALLATION NOTES +1. Set up MySQL and memcached. We run memcached with the command: + memcached -d -m 5120 -s /var/run/memcached.sock -a 0777 -t16 -C -u root + This gives it 5 gigs of RAM, you probably want to set that a bit lower! +2. Run gazelle.sql (preferably as root) to create the database, the table, and the default data. +3. Install sphinx - we recommend you use the included sphinx.conf + For documentation, read http://www.sphinxsearch.com/docs/current.html + + After you've installed, create the indices: + /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --all + +4. Move classes/config.template to classes/config.php. Edit the config.php as needed. + We use http://grc.com/passwords.html for our passwords - you'll be generating a lot of these. +5. Sign up. The first user is made a sysop! +6. Set up cron jobs. You need a cron job for the schedule, a cron job for +the peerupdate (all groups are cached, but the peer counts change often, +so peerupdate is a script to update them), and the two sphinx indices. +These are our cron jobs: + +0,15,30,45 * * * * /usr/local/bin/php /var/www/vhosts/what/schedule.php SCHEDULE_KEY >> /root/schedule.log +10,25,40,55 * * * * /usr/local/bin/php /var/www/vhosts/what/peerupdate.php SCHEDULE_KEY >> /root/peerupdate.log +* * * * * /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --rotate delta +5 0,12 * * * /usr/local/bin/indexer -c /etc/sphinx/sphinx.conf --rotate --all + +7. You're probably going to want geoip information, so first you need to fill in the geoip_country tables by visiting /tools.php?action=update_geoip . + After that finishes parsing information from maxmind, you'll may want to map users to countries by running: + "INSERT INTO users_geodistribution (Code, Users) SELECT g.Code, COUNT(u.ID) AS Users FROM geoip_country AS g JOIN users_main AS u ON INET_ATON(u.IP) BETWEEN g.StartIP AND g.EndIP WHERE u.Enabled='1' GROUP BY g.Code ORDER BY Users DESC" + This will fill in the table needed for stats. + +8. Start modifying stuff. Hopefully, everything will have gone smoothly so far and nothing will have exploded (ha ha ha) diff --git a/ajax.php b/ajax.php new file mode 100644 index 00000000..f214118b --- /dev/null +++ b/ajax.php @@ -0,0 +1 @@ + diff --git a/announce.php b/announce.php new file mode 100644 index 00000000..4f4c018f --- /dev/null +++ b/announce.php @@ -0,0 +1 @@ +d14:failure reason40:Invalid .torrent, try downloading again.e diff --git a/api.php b/api.php new file mode 100644 index 00000000..0b234fac --- /dev/null +++ b/api.php @@ -0,0 +1,116 @@ +handle_errors(); + +// Send a message to an IRC bot listening on SOCKET_LISTEN_PORT +function send_irc($Raw) { + $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT); + fwrite($IRCSocket, $Raw); + fclose($IRCSocket); +} + +function check_perms() { + return false; +} + +function error($Code) { + echo '',$Code,''; + die(); +} + +function make_secret($Length = 32) { + $Secret = ''; + $Chars='abcdefghijklmnopqrstuvwxyz0123456789'; + for($i=0; $i<$Length; $i++) { + $Rand = mt_rand(0, strlen($Chars)-1); + $Secret .= substr($Chars, $Rand, 1); + } + return str_shuffle($Secret); +} + +function is_number($Str) { + if ($Str < 0) { return false; } + // We're converting input to a int, then string and comparing to original + return ($Str == strval(intval($Str)) ? true : false); +} + +function display_str($Str) { + if ($Str!="") { + $Str=make_utf8($Str); + $Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8"); + $Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&",$Str); + + $Replace = array( + "'",'"',"<",">", + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $With=array( + ''','"','<','>', + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $Str=str_replace($Replace,$With,$Str); + } + return $Str; +} + +function make_utf8($Str) { + if ($Str!="") { + if (is_utf8($Str)) { $Encoding="UTF-8"; } + if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); } + if (empty($Encoding)) { $Encoding="ISO-8859-1"; } + if ($Encoding=="UTF-8") { return $Str; } + else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); } + } +} + +function is_utf8($Str) { + return preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] // ASCII + | [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16 + )*$%xs', $Str + ); +} + +function display_array($Array, $Escape = array()) { + foreach ($Array as $Key => $Val) { + if((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) { + $Array[$Key] = display_str($Val); + } + } + return $Array; +} + +header('Expires: '.date('D, d M Y H:i:s', time()+(2*60*60)).' GMT'); +header('Last-Modified: '.date('D, d M Y H:i:s').' GMT'); +header('Content-type: text/xml'); +echo ''; +require(SERVER_ROOT.'/sections/api/index.php'); +?> \ No newline at end of file diff --git a/artist.php b/artist.php new file mode 100644 index 00000000..3bccec6b --- /dev/null +++ b/artist.php @@ -0,0 +1,5 @@ +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 literal 0 HcmV?d00001 diff --git a/captcha/captcha3.png b/captcha/captcha3.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd5d31d38d537570b59d41a1b6f2886567c3ae1 GIT binary patch literal 10281 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 literal 0 HcmV?d00001 diff --git a/captcha/captcha4.png b/captcha/captcha4.png new file mode 100644 index 0000000000000000000000000000000000000000..ded013b54fbffa2c4aa7a47a4646afe494242842 GIT binary patch literal 33512 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
    )C=oW9lny&K`=t9@$1 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 M07*qoM6N<$f+~3kivR!s literal 0 HcmV?d00001 diff --git a/captcha/captcha8.png b/captcha/captcha8.png new file mode 100644 index 0000000000000000000000000000000000000000..5ab0c25d9ea1bb72214769aff67d4a0df11e41e6 GIT binary patch literal 33500 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 literal 0 HcmV?d00001 diff --git a/captcha/captcha9.png b/captcha/captcha9.png new file mode 100644 index 0000000000000000000000000000000000000000..66c17dce6f50f751f6dd6a06101d9fbb0c8bae8f GIT binary patch literal 42699 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 baR&Yco5rpYE2lJc00000NkvXXu0mjfZFnbK literal 0 HcmV?d00001 diff --git a/chat.php b/chat.php new file mode 100644 index 00000000..23061a3e --- /dev/null +++ b/chat.php @@ -0,0 +1,2 @@ +decrypt($_COOKIE['session']); } +if(isset($LoginCookie)) { + list($SessionID, $UserID)=explode("|~|",$Enc->decrypt($LoginCookie)); + + if(!$UserID || !$SessionID) { + die('Not logged in!'); + } + + if(!$Enabled = $Cache->get_value('enabled_'.$UserID)){ + require(SERVER_ROOT.'/classes/class_mysql.php'); //Require the database wrapper + $DB=NEW DB_MYSQL; //Load the database wrapper + $DB->query("SELECT Enabled FROM users_main WHERE ID='$UserID'"); + list($Enabled) = $DB->next_record(); + $Cache->cache_value('enabled_'.$UserID, $Enabled, 0); + } +} else { + die('Not logged in!'); +} + +function error($Error) { + die($Error); +} + +function is_number($Str) { + if ($Str < 0) { return false; } + // We're converting input to a int, then string and comparing to original + return ($Str == strval(intval($Str)) ? true : false); +} + +function display_str($Str) { + if ($Str!="") { + $Str=make_utf8($Str); + $Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8"); + $Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&",$Str); + + $Replace = array( + "'",'"',"<",">", + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $With=array( + ''','"','<','>', + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $Str=str_replace($Replace,$With,$Str); + } + return $Str; +} + +function make_utf8($Str) { + if ($Str!="") { + if (is_utf8($Str)) { $Encoding="UTF-8"; } + if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); } + if (empty($Encoding)) { $Encoding="ISO-8859-1"; } + if ($Encoding=="UTF-8") { return $Str; } + else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); } + } +} + +function is_utf8($Str) { + return preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] // ASCII + | [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16 + )*$%xs', $Str + ); +} + +function display_array($Array, $DontEscape = array()) { + foreach ($Array as $Key => $Val) { + if(!in_array($Key, $DontEscape)) { + $Array[$Key] = display_str($Val); + } + } + return $Array; +} + +function make_secret($Length = 32) { + $Secret = ''; + $Chars='abcdefghijklmnopqrstuvwxyz0123456789'; + for($i=0; $i<$Length; $i++) { + $Rand = mt_rand(0, strlen($Chars)-1); + $Secret .= substr($Chars, $Rand, 1); + } + return str_shuffle($Secret); +} + +// Send a message to an IRC bot listening on SOCKET_LISTEN_PORT +function send_irc($Raw) { + $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT); + $Raw = str_replace(array("\n", "\r"), '', $Raw); + fwrite($IRCSocket, $Raw); + fclose($IRCSocket); +} diff --git a/classes/class_alias.php b/classes/class_alias.php new file mode 100644 index 00000000..093ccbe2 --- /dev/null +++ b/classes/class_alias.php @@ -0,0 +1,65 @@ +query("SELECT Alias, ArticleID FROM wiki_aliases"); + $Aliases = $DB->to_array('Alias'); + $Cache->cache_value('wiki_aliases', $Aliases, 3600*24*14); + } + + function to_id($Alias) { + global $Cache, $DB; + $Aliases = $Cache->get_value('wiki_aliases'); + if(!$Aliases){ + $DB->query("SELECT Alias, ArticleID FROM wiki_aliases"); + $Aliases = $DB->to_array('Alias'); + $Cache->cache_value('wiki_aliases', $Aliases, 3600*24*14); + } + return $Aliases[$this->convert($Alias)]['ArticleID']; + } +/* + function flush() { + + } + + function to_id($Alias) { + global $DB; + $Alias = $this->convert($Alias); + $DB->query("SELECT ArticleID FROM wiki_aliases WHERE Alias LIKE '$Alias'"); + list($ArticleID) = $DB->next_record(); + return $ArticleID; + } +*/ + function article($ArticleID) { + global $Cache, $DB; + $Contents = $Cache->get_value('wiki_article_'.$ArticleID); + if(!$Contents){ + $DB->query("SELECT + w.Revision, + w.Title, + w.Body, + w.MinClassRead, + w.MinClassEdit, + w.Date, + w.Author, + u.Username, + GROUP_CONCAT(a.Alias), + GROUP_CONCAT(a.UserID) + FROM wiki_articles AS w + LEFT JOIN wiki_aliases AS a ON w.ID=a.ArticleID + LEFT JOIN users_main AS u ON u.ID=w.Author + WHERE w.ID='$ArticleID' + GROUP BY w.ID"); + if(!$DB->record_count()) { error(404); } + $Contents = $DB->to_array(); + $Cache->cache_value('wiki_article_'.$ArticleID, $Contents, 3600*24*14); + } + return $Contents; + } +} +?> diff --git a/classes/class_artist.php b/classes/class_artist.php new file mode 100644 index 00000000..547ef9af --- /dev/null +++ b/classes/class_artist.php @@ -0,0 +1,19 @@ +ID = $ID; + $this->NameLength = mb_strlen($Name, 'utf8'); + $this->Name = display_str($Name); + } + +} +?> diff --git a/classes/class_artists_similar.php b/classes/class_artists_similar.php new file mode 100644 index 00000000..f5464847 --- /dev/null +++ b/classes/class_artists_similar.php @@ -0,0 +1,372 @@ +1); + var $yValues = array(HEIGHT=>1); + + var $LargestDecimal = 0; + var $LowestDecimal = 1; + + + + function dump_data(){ + return serialize(array(time(), $this->Name, $this->x, $this->y, serialize($this->Artists), serialize($this->Similar))); + } + + function load_data($Data){ + list($LastUpdated, $this->Name, $this->x, $this->y, $this->Artists, $this->Similar) = unserialize($Data); + $this->Artists = unserialize($this->Artists); + $this->Similar = unserialize($this->Similar); + } + + function set_up(){ + $this->x = ceil(WIDTH/2); + $this->y = ceil(HEIGHT/2); + + $this->xValues[$this->x] = $this->ID; + $this->yValues[$this->y] = $this->ID; + + global $DB; + + // Get artists that are directly similar to the artist + $ArtistIDs = array(); + $DB->query(" + SELECT + s2.ArtistID, + ag.Name, + ass.Score + FROM artists_similar AS s1 + JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID + JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID + JOIN artists_group AS ag ON ag.ArtistID=s2.ArtistID + WHERE s1.ArtistID=".$this->ID." + ORDER BY ass.Score DESC + LIMIT 14"); + + if($DB->record_count() == 0){ + return; + } + + // Build into array. Each artist is its own object in $this->Artists + while(list($ArtistID, $Name, $Score) = $DB->next_record(MYSQLI_NUM, false)){ + if($Score<0){ + continue; + } + $this->Artists[$ArtistID] = new ARTIST($ArtistID, $Name); + $this->Similar[$ArtistID] = array('ID'=>$ArtistID,'Score'=>$Score); + $this->TotalScore+=$Score; + $ArtistIDs[]=$ArtistID; + } + + // Get similarities between artists on the map + $DB->query("SELECT + s1.ArtistID, + s2.ArtistID + FROM artists_similar AS s1 + JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID + JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID + JOIN artists_group AS a ON a.ArtistID=s2.ArtistID + WHERE s1.ArtistID IN(".implode(',',$ArtistIDs).") + AND s2.ArtistID IN(".implode(',',$ArtistIDs).") + "); + + // Build into array + while(list($Artist1ID, $Artist2ID) = $DB->next_record()){ + $this->Artists[$Artist1ID]->Similar[$Artist2ID] = array('ID'=>$Artist2ID); + } + + // Calculate decimal point scores between artists + foreach($this->Similar as $SimilarArtist) { + list($ArtistID, $Similar) = array_values($SimilarArtist); + $this->Similar[$ArtistID]['Decimal'] = $this->similarity($Similar['Score'], $this->TotalScore); + + if($this->Similar[$ArtistID]['Decimal'] < $this->LowestDecimal){ + $this->LowestDecimal = $this->Similar[$ArtistID]['Decimal']; + } + if($this->Similar[$ArtistID]['Decimal'] > $this->LargestDecimal){ + $this->LargestDecimal = $this->Similar[$ArtistID]['Decimal']; + } + } + reset($this->Artists); + } + + function set_positions(){ + $xValues = array(); // Possible x values + $Root = ceil(WIDTH/4); // Half-way into half of the image + $Offset = 4; // Distance from the root (a quarter of the way into the image) to the x value + + // The number of artists placed in the top or the bottom + $NumTop = 0; + $NumBottom = 0; + + // The number of artists placed in the left or the right + $NumLeft = 0; + $NumRight = 0; + + $Multiplier = 0; + + // Build up an impressive list of possible x values + // We later iterate through these, and pick out the ones we want + + // These x values are all below WIDTH/2 (all on the left) + // The script later chooses which side to put them on + + // We create more very low x values because they're more likely to be skipped + for($i = 0; $i<=count($this->Artists)*4; $i++){ + if($Offset>=((WIDTH/4))){ + $Offset=$Offset%(WIDTH/4); + } + $Plus = $Root+$Offset; // Point on the right of the root + $Minus = abs($Root-$Offset); // Point on the left of the root + + $xValues[$Plus]=$Plus; + + $xValues[$Minus]=$Minus; + + // Throw in an extra x value closer to the edge, because they're more likely to be skipped + + if($Minus>30){ + // $xValues[$Minus-30]=$Minus-30; + } + + $Offset = $Offset+rand(5,20); // Increase offset, and go again + } + + foreach($this->Artists as $Artist){ + $ArtistID = $Artist->ID; + if($Artist->Displayed == true){ + continue; + } + $this->Similar[$ArtistID]['Decimal'] = $this->Similar[$ArtistID]['Decimal'] * (1/($this->LargestDecimal))-0.1; + // Calculate the distance away from the center, based on similarity + $IdealDistance = $this->calculate_distance($this->Similar[$ArtistID]['Decimal'], $this->x, $this->y); + + $this->Similar[$ArtistID]['Distance'] = $IdealDistance; + + // 1 = left, 2 = right + $Horizontal = 0; + $Vertical = 0; + + // See if any similar artists have been placed yet. If so, place artist in that half + // (provided that there are enough in the other half to visually balance out) + reset($Artist->Similar); + foreach($Artist->Similar as $SimilarArtist) { + list($Artist2ID) = array_values($SimilarArtist); + if($this->Artists[$Artist2ID]) { + if($this->Artists[$Artist2ID]->x > (WIDTH/2) && ($NumRight-$NumLeft)<1){ + $Horizontal = 2; + } elseif($NumLeft-$NumRight<1) { + $Horizontal = 1; + } + break; + } + } + + shuffle($xValues); + + while($xValue = array_shift($xValues)){ + if(abs($this->x - $xValue) <= $IdealDistance) { + if(hypot(abs($this->x - $xValue), ($this->y - 50)) > $IdealDistance + || ceil(sqrt(pow($IdealDistance, 2) - pow($this->x - $xValue, 2))) > (HEIGHT/2)){ + $xValue = $this->x - ceil(sqrt(pow($IdealDistance, 2) - pow($IdealDistance*0.1*rand(5,9), 2))); + //echo "Had to change x value for ".$Artist->Name." to ".$xValue."\n"; + } + // Found a match (Is close enough to the center to satisfy $IdealDistance), + // Now it's time to choose which half to put it on + if(!$Horizontal) { + // No similar artists displayed + $Horizontal = ($NumLeft<$NumRight) ? 1 : 2; + } + if($Horizontal == 2){ + $xValue = WIDTH-$xValue; + $NumRight++; + } else { + $NumLeft++; + } + + $Artist->x = $xValue; + $this->xValues[$xValue] = $ArtistID; + unset($xValues[$xValue]); + + break; + } + } + if(!$xValue){ // Uh-oh, we were unable to choose an x value. + $xValue = ceil(sqrt(pow($IdealDistance, 2)/2)); + $xValue = (WIDTH/2)-$xValue; + $Artist->x = $xValue; + $this->xValues[$xValue] = $ArtistID; + unset($xValues[$xValue]); + } + + + // Pythagoras. $yValue is the vertical distance from the center to the y value + $yValue = sqrt(pow($IdealDistance, 2) - pow(abs($this->x - $Artist->x), 2)); + + + // Now we pick if it should go on the top or bottom + + if($NumTop>$NumBottom){ // Send it to the bottom half + $yValue=(HEIGHT/2)+$yValue; + $NumBottom++; + } else { + $yValue=(HEIGHT/2)-$yValue; + $NumTop++; + } + + $yValue = ceil($yValue); + + // $yValue is now a proper y coordinate + // Now time to do some spacing out + + if($yValue < 10){ + $yValue+=(10+abs($yValue))+rand(10,20); + } + + if($yValue > (HEIGHT - 10)){ + $yValue-=((HEIGHT/2)-rand(10,20)); + } + + $i = 1; + while($Conflict = $this->scan_array_range($this->yValues, abs($yValue-13), $yValue+13)) { + if($i > 10){ + break; + } + if(!$this->scan_array_range($this->yValues, abs($yValue-5), $yValue-20)){ + $yValue -= 20; + } + + $yValue=$Conflict + rand(10, 20); + if($yValue>HEIGHT-10){ + $yValue-=ceil(HEIGHT/2.5); + } elseif($yValue<10) { + $yValue+=ceil(HEIGHT/2.5); + } + $i++; + } + + $Artist->y = $yValue; + $this->yValues[$yValue] = $ArtistID; + } + reset($this->Artists); + reset($this->xValues); + reset($this->yValues); + + } + + // Calculate the ideal distance from the center point ($Rootx, $Rooty) to the artist's point on the board + // Pythagoras as fun! + function calculate_distance($SimilarityCoefficient, $Rootx, $Rooty){ + $MaxWidth = WIDTH - $Rootx; + $MaxHeight = HEIGHT - $Rooty; + $x = $MaxWidth - ($SimilarityCoefficient*$MaxWidth*.01); // Possible x value + $y = $MaxHeight - ($SimilarityCoefficient*$MaxHeight); // Possible y value + $Hypot = hypot($Rootx - $x, $Rooty - $y); + return $MaxWidth - $Hypot; + + } + + function similarity($Score, $TotalArtistScore){ + return (pow(($Score/($TotalArtistScore+1)), (1/1))); + } + + function scan_array_range($Array, $Start, $Finish){ + if($Start<0){ + die($Start); + } + for ($i = $Start; $i<=$Finish; $i++){ + if(isset($Array[$i])){ + return $i; + } + } + return false; + } + + function write_artists(){ +?> +
    + Name?> +
    +Artists as $Artist){ + if($Artist->ID == $this->ID){ + continue; + } + $xPosition = $Artist->x - $Artist->NameLength*4; + if($xPosition<0){ + $xPosition=3; + $Artist->x = $xPosition; + + } + $Decimal = $this->Similar[$Artist->ID]['Decimal']; + + if($Decimal<0.2){ + $FontSize = 8; + } elseif($Decimal<0.3){ + $FontSize = 9; + } elseif($Decimal<0.4){ + $FontSize = 10; + } else { + $FontSize = 12; + } +?> +
    +Artists); + } + + function background_image(){ + global $Img; + reset($this->Similar); + foreach($this->Similar as $SimilarArtist) { + list($ArtistID, $Val) = array_values($SimilarArtist); + $Artist = $this->Artists[$ArtistID]; + $Decimal = $this->Similar[$ArtistID]['Decimal']; + $Width = ceil($Decimal*4)+1; + + $Img->line($this->x, $this->y, $Artist->x, $Artist->y,$Img->color(199,218,255), $Width); + + unset($Artist->Similar[$this->ID]); + reset($Artist->Similar); + foreach($Artist->Similar as $SimilarArtist2) { + list($Artist2ID) = array_values($SimilarArtist2); + if($this->Artists[$Artist2ID]){ + $Artist2 = $this->Artists[$Artist2ID]; + $Img->line($Artist->x, $Artist->y, $Artist2->x, $Artist2->y,$Img->color(173,201,255)); + unset($Artist2->Similar[$ArtistID]); + } + } + reset($this->xValues); + } + + $Img->make_png(SERVER_ROOT.'/static/similar/'.$this->ID.'.png'); + } + + function dump(){ + echo "Similarities:\n"; + foreach($this->Artists as $Artist){ + echo $Artist->ID; + echo ' - '; + echo $Artist->Name; + echo "\n"; + echo "x - ".$Artist->x."\n"; + echo "y - ".$Artist->y."\n"; + print_r($this->Similar[$Artist->ID]); + //print_r($Artist->Similar); + echo "\n\n---\n\n"; + } + + } + + +} + + +?> diff --git a/classes/class_cache.php b/classes/class_cache.php new file mode 100644 index 00000000..cde26a0d --- /dev/null +++ b/classes/class_cache.php @@ -0,0 +1,325 @@ +pconnect(MEMCACHED_HOST, MEMCACHED_PORT); + + //$this->connect('localhost', 11211); + } + + //---------- Caching functions ----------// + + // Allows us to set an expiration on otherwise perminantly cache'd values + // Useful for disabled users, locked threads, basically reducing ram usage + public function expire_value($Key, $Duration=2592000) { + $StartTime=microtime(true); + $this->set($Key, $this->get($Key), $Duration); + $this->Time+=(microtime(true)-$StartTime)*1000; + } + + // Wrapper for Memcache::set, with the zlib option removed and default duration of 30 days + public function cache_value($Key, $Value, $Duration=2592000) { + $StartTime=microtime(true); + if (empty($Key)) { + trigger_error("Cache insert failed for empty key"); + } + if (!$this->set($Key, $Value, 0, $Duration)) { + trigger_error("Cache insert failed for key $Key"); + } + $this->Time+=(microtime(true)-$StartTime)*1000; + } + + public function replace_value($Key, $Value, $Duration=2592000) { + $StartTime=microtime(true); + $this->replace($Key, $Value, false, $Duration); + $this->Time+=(microtime(true)-$StartTime)*1000; + } + + public function get_value($Key, $NoCache=false) { + $StartTime=microtime(true); + if (empty($Key)) { + trigger_error("Cache retrieval failed for empty key"); + } + + if (isset($_GET['clearcache']) && $this->CanClear && !in_array_partial($Key, $this->PersistentKeys)) { + if ($_GET['clearcache'] == 1) { + //Because check_perms isn't true until loggeduser is pulled from the cache, we have to remove the entries loaded before the loggeduser data + //Because of this, not user cache data will require a secondary pageload following the clearcache to update + if (count($this->CacheHits) > 0) { + foreach (array_keys($this->CacheHits) as $HitKey) { + if (!in_array_partial($HitKey, $this->PersistentKeys)) { + $this->delete($HitKey); + unset($this->CacheHits[$HitKey]); + } + } + } + $this->delete($Key); + $this->Time+=(microtime(true)-$StartTime)*1000; + return false; + } elseif ($_GET['clearcache'] == $Key) { + $this->delete($Key); + $this->Time+=(microtime(true)-$StartTime)*1000; + return false; + } elseif (in_array($_GET['clearcache'], $this->CacheHits)) { + unset($this->CacheHits[$_GET['clearcache']]); + $this->delete($_GET['clearcache']); + } + } + + //For cases like the forums, if a keys already loaded grab the existing pointer + if (isset($this->CacheHits[$Key]) && !$NoCache) { + $this->Time+=(microtime(true)-$StartTime)*1000; + return $this->CacheHits[$Key]; + } + + $Return = $this->get($Key); + if ($Return !== false && !$NoCache) { + $this->CacheHits[$Key] = $Return; + } + $this->Time+=(microtime(true)-$StartTime)*1000; + return $Return; + } + + // Wrapper for Memcache::delete. For a reason, see above. + public function delete_value($Key) { + $StartTime=microtime(true); + if (empty($Key)) { + trigger_error("Cache deletion failed for empty key"); + } + if (!$this->delete($Key)) { + //trigger_error("Cache delete failed for key $Key"); + } + $this->Time+=(microtime(true)-$StartTime)*1000; + } + + //---------- memcachedb functions ----------// + + public function begin_transaction($Key) { + $Value = $this->get($Key); + if (!is_array($Value)) { + $this->InTransaction = false; + $this->MemcacheDBKey = array(); + $this->MemcacheDBKey = ''; + return false; + } + $this->MemcacheDBArray = $Value; + $this->MemcacheDBKey = $Key; + $this->InTransaction = true; + return true; + } + + public function cancel_transaction() { + $this->InTransaction = false; + $this->MemcacheDBKey = array(); + $this->MemcacheDBKey = ''; + } + + public function commit_transaction($Time=2592000) { + if (!$this->InTransaction) { + return false; + } + $this->cache_value($this->MemcacheDBKey, $this->MemcacheDBArray, $Time); + $this->InTransaction = false; + } + + // Updates multiple rows in an array + public function update_transaction($Rows, $Values) { + if (!$this->InTransaction) { + return false; + } + $Array = $this->MemcacheDBArray; + if (is_array($Rows)) { + $i = 0; + $Keys = $Rows[0]; + $Property = $Rows[1]; + foreach ($Keys as $Row) { + $Array[$Row][$Property] = $Values[$i]; + $i++; + } + } else { + $Array[$Rows] = $Values; + } + $this->MemcacheDBArray = $Array; + } + + // Updates multiple values in a single row in an array + // $Values must be an associative array with key:value pairs like in the array we're updating + public function update_row($Row, $Values) { + if (!$this->InTransaction) { + return false; + } + if ($Row === false) { + $UpdateArray = $this->MemcacheDBArray; + } else { + $UpdateArray = $this->MemcacheDBArray[$Row]; + } + foreach ($Values as $Key => $Value) { + if (!array_key_exists($Key, $UpdateArray)) { + trigger_error('Bad transaction key ('.$Key.') for cache '.$this->MemcacheDBKey); + } + if ($Value === '+1') { + if (!is_number($UpdateArray[$Key])) { + trigger_error('Tried to increment non-number ('.$Key.') for cache '.$this->MemcacheDBKey); + } + ++$UpdateArray[$Key]; // Increment value + } elseif ($Value === '-1') { + if (!is_number($UpdateArray[$Key])) { + trigger_error('Tried to decrement non-number ('.$Key.') for cache '.$this->MemcacheDBKey); + } + --$UpdateArray[$Key]; // Decrement value + } else { + $UpdateArray[$Key] = $Value; // Otherwise, just alter value + } + } + if ($Row === false) { + $this->MemcacheDBArray = $UpdateArray; + } else { + $this->MemcacheDBArray[$Row] = $UpdateArray; + } + } + + // Increments multiple values in a single row in an array + // $Values must be an associative array with key:value pairs like in the array we're updating + public function increment_row($Row, $Values) { + if (!$this->InTransaction) { + return false; + } + if ($Row === false) { + $UpdateArray = $this->MemcacheDBArray; + } else { + $UpdateArray = $this->MemcacheDBArray[$Row]; + } + foreach ($Values as $Key => $Value) { + if (!array_key_exists($Key, $UpdateArray)) { + trigger_error('Bad transaction key ('.$Key.') for cache '.$this->MemcacheDBKey); + } + if (!is_number($Value)) { + trigger_error('Tried to increment with non-number ('.$Key.') for cache '.$this->MemcacheDBKey); + } + $UpdateArray[$Key] += $Value; // Increment value + } + if ($Row === false) { + $this->MemcacheDBArray = $UpdateArray; + } else { + $this->MemcacheDBArray[$Row] = $UpdateArray; + } + } + + // Insert a value at the beginning of the array + public function insert_front($Key, $Value) { + if (!$this->InTransaction) { + return false; + } + if ($Key === '') { + array_unshift($this->MemcacheDBArray, $Value); + } else { + $this->MemcacheDBArray = array($Key=>$Value) + $this->MemcacheDBArray; + } + } + + // Insert a value at the end of the array + public function insert_back($Key, $Value) { + if (!$this->InTransaction) { + return false; + } + if ($Key === '') { + array_push($this->MemcacheDBArray, $Value); + } else { + $this->MemcacheDBArray = $this->MemcacheDBArray + array($Key=>$Value); + } + + } + + public function insert($Key, $Value) { + if (!$this->InTransaction) { + return false; + } + if ($Key === '') { + $this->MemcacheDBArray[] = $Value; + } else { + $this->MemcacheDBArray[$Key] = $Value; + } + } + + public function delete_row($Row) { + if (!$this->InTransaction) { + return false; + } + if (!isset($this->MemcacheDBArray[$Row])) { + trigger_error('Tried to delete non-existent row ('.$Row.') for cache '.$this->MemcacheDBKey); + } + unset($this->MemcacheDBArray[$Row]); + } + + public function update($Key, $Rows, $Values, $Time=2592000) { + if (!$this->InTransaction) { + $this->begin_transaction($Key); + $this->update_transaction($Rows, $Values); + $this->commit_transaction($Time); + } else { + $this->update_transaction($Rows, $Values); + } + + } + + // Built-in increment/decrement functions are said not to be thread safe +/* Supposedly fixed in v1.4.6 + public function increment($Key, $Value=1) { + if(($OldValue = $this->get($Key)) === false || !is_number($Value)) { + return false; + } + $this->replace_value($Key, $OldValue+$Value); + } + + public function decrement($Key, $Value=1) { + if(($OldValue = $this->get($Key)) === false || !is_number($Value) || !is_number($OldValue)) { + return false; + } + if($Value > $OldValue) { + $OldValue = $Value = 0; + } + $this->replace_value($Key, $OldValue-$Value); + } +*/ +} diff --git a/classes/class_charts.php b/classes/class_charts.php new file mode 100644 index 00000000..dfb4b690 --- /dev/null +++ b/classes/class_charts.php @@ -0,0 +1,193 @@ + 300000 || $Height > 1000 || $Width > 1000) { + trigger_error('Tried to make chart too large.'); + } + $this->URL .= '?cht='.$Type.'&chs='.$Width.'x'.$Height; + $this->Options = $Options; + } + + protected function encode($Number) { + if ($Number == -1) { + return '__'; + } + $CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.'; + return $CharKey[floor($Number/64)].$CharKey[floor($Number%64)]; + } + + public function color($Colors) { + $this->URL .= '&chco='.$Colors; + } + + public function lines($Thickness, $Solid=1, $Blank=0) { + $this->URL .= '&chls='.$Thickness.','.$Solid.','.$Blank; + } + + public function title($Title, $Color='', $Size='') { + $this->URL .= '&chtt='.str_replace(array(' ',"\n"), array('+','|'), $Title); + if (!empty($Color)) { + $this->URL .= '&chts='.$Color; + } + if (!empty($Size)) { + $this->URL .= ','.$Size; + } + } + + public function legend($Items, $Placement='') { + $this->URL .= '&chdl='.str_replace(' ', '+', implode('|', $Items)); + if (!empty($Placement)) { + if (!in_array($Placement, array('b','t','r','l','bv','tv'))) { + trigger_error('Invalid legend placement.'); + } + $this->URL .= '&chdlp='.$Placement; + } + } + + public function add($Label, $Data) { + if ($Label !== false) { + $this->Labels[] = $Label; + } + $this->Data[] = $Data; + } + + public function grid_lines($SpacingX=0, $SpacingY=-1, $Solid=1, $Blank=1) { + //Can take 2 more parameters for offset, but we're not bothering with that right now + $this->URL .= '&chg='.$SpacingX.','.$SpacingY.','.$Solid.','.$Blank.''; + } + + public function transparent() { + $this->URL .= '&chf=bg,s,FFFFFF00'; + } + + + public function url() { + return $this->URL; + } +} + +class AREA_GRAPH extends GOOGLE_CHARTS { + public function __construct ($Width, $Height, $Options=array()) { + parent::__construct('lc', $Width, $Height, $Options); + } + + public function color ($Color) { + $this->URL .= '&chco='.$Color.'&chm=B,'.$Color.'50,0,0,0'; + } + + public function generate() { + $Max = max($this->Data); + $Min = (isset($this->Options['Break']))?$Min=min($this->Data):0; + $Data = array(); + foreach ($this->Data as $Value) { + $Data[] = $this->encode((($Value-$Min)/($Max-$Min))*4095); + } + $this->URL .= "&chxt=y,x&chxs=0,h&chxl=1:|".implode('|', $this->Labels).'&chxr=0,'.$Min.','.($Max-$Min).'&chd=e:'.implode('', $Data); + } +} + +class PIE_CHART extends GOOGLE_CHARTS { + public function __construct ($Width, $Height, $Options=array()) { + $Type = (isset($this->Options['3D']))?'p3':'p'; + parent::__construct($Type, $Width, $Height, $Options); + } + + public function generate() { + $Sum = array_sum($this->Data); + $Other = isset($this->Options['Other']); + $Sort = isset($this->Options['Sort']); + $LabelPercent = isset($this->Options['Percentage']); + + if ($Sort && !empty($this->Labels)) { + array_multisort($this->Data, SORT_DESC, $this->Labels); + } elseif ($Sort) { + sort($this->Data); + $this->Data = array_reverse($this->Data); + } + + $Data = array(); + $Labels = $this->Labels; + $OtherPercentage = 0.00; + $OtherData = 0; + + foreach ($this->Data as $Key => $Value) { + $ThisPercentage = number_format(($Value/$Sum)*100, 2); + $ThisData = ($Value/$Sum)*4095; + if ($Other && $ThisPercentage < 1) { + $OtherPercentage += $ThisPercentage; + $OtherData += $ThisData; + unset($Data[$Key]); + unset($Labels[$Key]); + continue; + } + if ($LabelPercent) { + $Labels[$Key] .= ' ('.$ThisPercentage.'%)'; + } + $Data[] = $this->encode($ThisData); + } + if ($OtherPercentage > 0) { + $OtherLabel = 'Other'; + if ($LabelPercent) { + $OtherLabel .= ' ('.$OtherPercentage.'%)'; + } + $Labels[] = $OtherLabel; + $Data[] = $this->encode($OtherData); + } + $this->URL .= "&chl=".implode('|', $Labels).'&chd=e:'.implode('', $Data); + } +} + + +class LOG_BAR_GRAPH extends GOOGLE_CHARTS { + //TODO: Finish. + public function __construct ($Base, $Width, $Height, $Options=array()) { + parent::__construct('lc', $Width, $Height, $Options); + } + + public function color ($Color) { + $this->URL .= '&chco='.$Color.'&chm=B,'.$Color.'50,0,0,0'; + } + + public function generate() { + $Max = max($this->Data); + $Min = (isset($this->Options['Break']))?$Min=min($this->Data):0; + $Data = array(); + foreach ($this->Data as $Value) { + $Data[] = $this->encode((($Value-$Min)/($Max-$Min))*4095); + } + $this->URL .= "&chxt=y,x&chxs=0,h&chxl=1:|".implode('|', $this->Labels).'&chxr=0,'.$Min.','.($Max-$Min).'&chd=e:'.implode('', $Data); + } +} + +class POLL_GRAPH extends GOOGLE_CHARTS { + public function __construct () { + $this->URL .= '?cht=bhg'; + } + + public function add($Label, $Data) { + if ($Label !== false) { + $this->Labels[] = cut_string($Label,35); + } + $this->Data[] = $Data; + } + + public function generate() { + $Count = count($this->Data); + $Height = (30*$Count)+20; + $Max = max($this->Data); + $Sum = array_sum($this->Data); + $Increment = ($Max/$Sum)*25; // * 100% / 4divisions + $Data = array(); + $Labels = array(); + foreach ($this->Data as $Key => $Value) { + $Data[] = $this->encode(($Value/$Max)*4095); + $Labels[] = '@t'.str_replace(array(' ',','),array('+','\,'),$this->Labels[$Key]).',000000,1,'.round((($Key + 1)/$Count) - (12/$Height),2).':0,12'; + } + $this->URL .= "&chbh=25,0,5&chs=214x$Height&chl=0%|".round($Increment,1)."%|".round($Increment * 2,1)."%|".round($Increment * 3,1)."%|".round($Increment * 4,1)."%&chm=".implode('|', $Labels).'&chd=e:'.implode('', $Data); + } +} diff --git a/classes/class_cookie.php b/classes/class_cookie.php new file mode 100644 index 00000000..365de3e4 --- /dev/null +++ b/classes/class_cookie.php @@ -0,0 +1,48 @@ +get(); is user provided and untrustworthy + +|*************************************************************************/ + +/* +interface COOKIE_INTERFACE { + public function get($Key); + public function set($Key,$Value,$Seconds,$LimitAccess); + public function del($Key); + + public function flush(); +} +*/ + +class COOKIE /*implements COOKIE_INTERFACE*/ { + const LIMIT_ACCESS = true; //If true, blocks JS cookie API access by default (can be overridden case by case) + const PREFIX = ''; //In some cases you may desire to prefix your cookies + + public function get($Key) { + if (!isset($_COOKIE[SELF::PREFIX.$Key])) { + return false; + } + return $_COOKIE[SELF::PREFIX.$Key]; + } + + //Pass the 4th optional param as false to allow JS access to the cookie + public function set($Key,$Value,$Seconds = 86400,$LimitAccess = SELF::LIMIT_ACCESS) { + setcookie(SELF::PREFIX.$Key,$Value,time()+$Seconds,'/',SITE_URL,$_SERVER['SERVER_PORT'] === '443',$LimitAccess,false); + } + + public function del($Key) { + setcookie(SELF::PREFIX.$Key,'',time()-24*3600); //3600 vs 1 second to account for potential clock desyncs + } + + public function flush() { + $Cookies = array_keys($_COOKIE); + foreach ($Cookies as $Cookie) { + $this->del($Cookie); + } + } +} diff --git a/classes/class_debug.php b/classes/class_debug.php new file mode 100644 index 00000000..98d8a513 --- /dev/null +++ b/classes/class_debug.php @@ -0,0 +1,536 @@ + MAX_TIME && !defined('TIME_EXCEPTION')) { + $Reason[] = number_format($Micro, 3).' ms'; + } + + $Errors = count($this->get_errors()); + if ($Errors > MAX_ERRORS && !defined('ERROR_EXCEPTION')) { + $Reason[] = $Errors.' PHP Errors'; + } + /* + $Queries = count($this->get_queries()); + if ($Queries > MAX_QUERIES && !defined('QUERY_EXCEPTION')) { + $Reason[] = $Queries.' Queries'; + } + */ + $Ram = memory_get_usage(true); + if ($Ram > MAX_MEMORY && !defined('MEMORY_EXCEPTION')) { + $Reason[] = get_size($Ram).' Ram Used'; + } + + if (isset($_REQUEST['profile'])) { + global $LoggedUser; + $Reason[] = 'Requested by '.$LoggedUser['Username']; + } + + if (isset($Reason[0])) { + $this->analysis(implode(', ', $Reason)); + return true; + } + + return false; + } + + public function analysis($Message, $Report='', $Time=43200) { + global $Cache, $Document; + if (empty($Report)) { + $Report = $Message; + } + $Identifier = make_secret(5); + $Cache->cache_value( + 'analysis_'.$Identifier, + array( + 'url' => $_SERVER['REQUEST_URI'], + 'message' => $Report, + 'errors' => $this->get_errors(true), + 'queries' => $this->get_queries(), + 'flags' => $this->get_flags(), + 'includes' => $this->get_includes(), + 'cache' => $this->get_cache_keys(), + 'vars' => $this->get_logged_vars() + ), + $Time + ); + send_irc('PRIVMSG '.LAB_CHAN.' :'.$Message.' '.$Document.' '.' http://'.NONSSL_SITE_URL.'/tools.php?action=analysis&case='.$Identifier.' http://'.NONSSL_SITE_URL.$_SERVER['REQUEST_URI']); + } + + public function log_var($Var, $VarName = FALSE) { + $BackTrace = debug_backtrace(); + $ID = uniqid(); + if(!$VarName) { + $VarName = $ID; + } + $File = array('path' => substr($BackTrace[0]['file'], strlen(SERVER_ROOT)), 'line' => $BackTrace[0]['line']); + $this->LoggedVars[$ID] = array($VarName => array('bt' => $File, 'data' => $Var)); + } + + public function set_flag($Event) { + global $ScriptStartTime; + $this->Flags[] = array($Event,(microtime(true)-$ScriptStartTime)*1000,memory_get_usage(true)); + } + + //This isn't in the constructor because $this is not available, and the function cannot be made static + public function handle_errors() { + //error_reporting(E_ALL ^ E_STRICT | E_WARNING | E_DEPRECATED | E_ERROR | E_PARSE); //E_STRICT disabled + error_reporting(E_WARNING | E_ERROR | E_PARSE); + set_error_handler(array($this, 'php_error_handler')); + } + + protected function format_args($Array) { + $LastKey = -1; + $Return = array(); + foreach ($Array as $Key => $Val) { + $Return[$Key] = ''; + if (!is_int($Key) || $Key != $LastKey+1) { + $Return[$Key] .= "'$Key' => "; + } + if ($Val === true) { + $Return[$Key] .= "true"; + } elseif ($Val === false) { + $Return[$Key] .= "false"; + } elseif (is_string($Val)) { + $Return[$Key] .= "'$Val'"; + } elseif (is_int($Val)) { + $Return[$Key] .= $Val; + } elseif (is_object($Val)) { + $Return[$Key] .= get_class($Val); + } elseif (is_array($Val)) { + $Return[$Key] .= 'array('.$this->format_args($Val).')'; + } + $LastKey = $Key; + } + return implode(', ', $Return); + } + + public function php_error_handler($Level, $Error, $File, $Line) { + //Who added this, it's still something to pay attention to... + if (stripos('Undefined index', $Error) !== false) { + //return true; + } + + $Steps = 1; //Steps to go up in backtrace, default one + $Call = ''; + $Args = ''; + $Tracer = debug_backtrace(); + + //This is in case something in this function goes wrong and we get stuck with an infinite loop + if (isset($Tracer[$Steps]['function'], $Tracer[$Steps]['class']) && $Tracer[$Steps]['function'] == 'php_error_handler' && $Tracer[$Steps]['class'] == 'DEBUG') { + return true; + } + + //If this error was thrown, we return the function which threw it + if (isset($Tracer[$Steps]['function']) && $Tracer[$Steps]['function'] == 'trigger_error') { + $Steps++; + $File = $Tracer[$Steps]['file']; + $Line = $Tracer[$Steps]['line']; + } + + //At this time ONLY Array strict typing is fully supported. + //Allow us to abuse strict typing (IE: function test(Array)) + if (preg_match('/^Argument (\d+) passed to \S+ must be an (array), (array|string|integer|double|object) given, called in (\S+) on line (\d+) and defined$/', $Error, $Matches)) { + $Error = 'Type hinting failed on arg '.$Matches[1]. ', expected '.$Matches[2].' but found '.$Matches[3]; + $File = $Matches[4]; + $Line = $Matches[5]; + } + + //Lets not be repetative + if (($Tracer[$Steps]['function'] == 'include' || $Tracer[$Steps]['function'] == 'require' ) && isset($Tracer[$Steps]['args'][0]) && $Tracer[$Steps]['args'][0] == $File) { + unset($Tracer[$Steps]['args']); + } + + //Class + if (isset($Tracer[$Steps]['class'])) { + $Call .= $Tracer[$Steps]['class'].'::'; + } + + //Function & args + if (isset($Tracer[$Steps]['function'])) { + $Call .= $Tracer[$Steps]['function']; + if (isset($Tracer[$Steps]['args'][0])) { + $Args = $this->format_args($Tracer[$Steps]['args']); + } + } + + //Shorten the path & we're done + $File = str_replace(SERVER_ROOT, '', $File); + $Error = str_replace(SERVER_ROOT, '', $Error); + + /* + //Hiding "session_start(): Server 10.10.0.1 (tcp 11211) failed with: No route to host (113)" errors + if($Call != "session_start") { + $this->Errors[] = array($Error, $File.':'.$Line, $Call, $Args); + } + */ + return true; + } + + /* Data wrappers */ + + public function get_flags() { + return $this->Flags; + } + + public function get_errors($Light=false) { + //Because the cache can't take some of these variables + if ($Light) { + foreach ($this->Errors as $Key => $Value) { + $this->Errors[$Key][3] = ''; + } + } + return $this->Errors; + } + + public function get_constants() { + return get_defined_constants(true); + } + + public function get_classes() { + foreach (get_declared_classes() as $Class) { + $Classes[$Class]['Vars'] = get_class_vars($Class); + $Classes[$Class]['Functions'] = get_class_methods($Class); + } + return $Classes; + } + + public function get_extensions() { + foreach (get_loaded_extensions() as $Extension) { + $Extensions[$Extension]['Functions'] = get_extension_funcs($Extension); + } + return $Extensions; + } + + public function get_includes() { + return get_included_files(); + } + + public function get_cache_time() { + global $Cache; + return $Cache->Time; + } + + public function get_cache_keys() { + global $Cache; + return array_keys($Cache->CacheHits); + } + + public function get_sphinx_queries() { + global $SS; + return $SS->Queries; + } + + public function get_sphinx_time() { + global $SS; + return $SS->Time; + } + + public function get_queries() { + global $DB; + return $DB->Queries; + } + + public function get_query_time() { + global $DB; + return $DB->Time; + } + + public function get_logged_vars() { + return $this->LoggedVars; + } + + /* Output Formatting */ + + public function include_table($Includes=false) { + if (!is_array($Includes)) { + $Includes = $this->get_includes(); + } +?> + + + + +
    (View) Includes:
    + + + + + + + +get_classes(); + } +?> + + + + +
    (View) Classes:
    + + + + + + + + + + +
    (View) Extensions:
    + + + + + +get_flags(); + } + if (empty($Flags)) { + return; + } +?> + + + + +
    (View) Flags:
    + + + + + + + + + +get_constants(); + } +?> + + + + +
    (View) Constants:
    + + + + + +get_cache_keys(); + $Header .= ' ('.number_format($this->get_cache_time(), 5).' ms)'; + } + if (empty($CacheKeys)) { + return; + } + $Header = ' '.number_format(count($CacheKeys)).' '.$Header.':'; + +?> + + + + +
    (View)
    + + + + + + + + +get_errors(); + } + if (empty($Errors)) { + return; + } +?> + + + + +
    (View) Errors:
    + + + + + + + + + +get_queries(); + $Header .= ' ('.number_format($this->get_query_time(), 5).' ms)'; + } + if (empty($Queries)) { + return; + } + $Header = ' '.number_format(count($Queries)).' '.$Header.':'; +?> + + + + +
    (View)
    + + + + + + + + +get_sphinx_queries(); + $Header .= ' ('.number_format($this->get_sphinx_time(), 5).' ms)'; + } + if (empty($Queries)) { + return; + } + $Header = ' '.number_format(count($Queries)).' '.$Header.':'; +?> + + + + +
    (View)
    + + + + + + + + +LoggedVars)) { + return; + } + $Vars = $this->LoggedVars; + } + $Header = ' '.number_format(count($Vars)).' '.$Header.':'; + +?> + + + + +
    (View)
    + + $Var) { + list($Key, $Data) = each($Var); + $Size = count($Data['data']); +?> + + + + + + + diff --git a/classes/class_feed.php b/classes/class_feed.php new file mode 100644 index 00000000..5d472b62 --- /dev/null +++ b/classes/class_feed.php @@ -0,0 +1,70 @@ +\n","\n\t\n"; + } + function close_feed() { + echo "\t\n"; + } + function channel($Title, $Description, $Section='') { + $Site = $this->UseSSL ? 'https://'.SSL_SITE_URL : 'http://'.NONSSL_SITE_URL; + echo "\t\t$Title :: ". SITE_NAME. "\n"; + echo "\t\t$Site/$Section\n"; + echo "\t\t$Description\n"; + echo "\t\ten-us\n"; + echo "\t\t". date('r'). "\n"; + echo "\t\thttp://blogs.law.harvard.edu/tech/rss\n"; + echo "\t\tGazelle Feed Class\n\n"; + } + function item($Title, $Description, $Page, $Creator, $Comments='', $Category='', $Date='') { //Escape with CDATA, otherwise the feed breaks. + if ($Date == '') { + $Date = date("r"); + } else { + $Date = date("r",strtotime($Date)); + } + $Site = $this->UseSSL ? 'https://'.SSL_SITE_URL : 'http://'.NONSSL_SITE_URL; + $Item = "\t\t\n"; + $Item .= "\t\t\t<![CDATA[$Title]]>\n"; + $Item .= "\t\t\t\n"; + $Item .= "\t\t\t$Date\n"; + $Item .= "\t\t\t$Site/$Page\n"; + $Item .= "\t\t\t$Site/$Page\n"; + if ($Comments != '') { + $Item .= "\t\t\t$Site/$Comments\n"; + } + if ($Category != '') { + $Item .= "\t\t\t\n"; + } + $Item .= "\t\t\t$Creator\n\t\t\n"; + return $Item; + } + + function retrieve($CacheKey,$AuthKey,$PassKey) { + global $Cache; + $Entries = $Cache->get_value($CacheKey); + if(!$Entries){ + $Entries = array(); + } else { + foreach($Entries as $Item){ + echo str_replace(array('[[PASSKEY]]','[[AUTHKEY]]'),array(display_str($PassKey),display_str($AuthKey)),$Item); + } + } + } + + function populate($CacheKey,$Item) { + global $Cache; + $Entries = $Cache->get_value($CacheKey,true); + if(!$Entries){ + $Entries = array(); + } else { + if(count($Entries)>=50) { + array_pop($Entries); + } + } + array_unshift($Entries, $Item); + $Cache->cache_value($CacheKey, $Entries, 0); //inf cache + } +} diff --git a/classes/class_image.php b/classes/class_image.php new file mode 100644 index 00000000..24ec44d4 --- /dev/null +++ b/classes/class_image.php @@ -0,0 +1,58 @@ +Image = imagecreate($Width, $Height); + $this->Font = SERVER_ROOT.'/classes/fonts/VERDANA.TTF'; + if(function_exists('imageantialias')){ + imageantialias($this->Image, true); + } + } + + function color($Red, $Green, $Blue, $Alpha=0){ + return imagecolorallocatealpha($this->Image, $Red, $Green, $Blue, $Alpha); + } + + function line($x1, $y1, $x2, $y2, $Color, $Thickness = 1){ + if($Thickness == 1){ + return imageline($this->Image, $x1, $y1, $x2, $y2, $Color); + } + $t = $Thickness / 2 - 0.5; + if ($x1 == $x2 || $y1 == $y2) { + return imagefilledrectangle($this->Image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color); + } + $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q + $a = $t / sqrt(1 + pow($k, 2)); + $Points = array( + round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a), + round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a), + round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a), + round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a), + ); + imagefilledpolygon($this->Image, $Points, 4, $Color); + return imagepolygon($this->Image, $Points, 4, $Color); + } + + function ellipse($x, $y, $Width, $Height, $Color){ + return imageEllipse($this->Image, $x, $y, $Width, $Height, $Color); + } + + function text($x, $y, $Color, $Text){ + return imagettftext ($this->Image, $this->FontSize,$this->TextAngle, $x, $y, $Color, $this->Font, $Text); + } + + function make_png($FileName = NULL){ + return imagepng($this->Image, $FileName); + } + + +} +?> diff --git a/classes/class_invite_tree.php b/classes/class_invite_tree.php new file mode 100644 index 00000000..a6ac25e8 --- /dev/null +++ b/classes/class_invite_tree.php @@ -0,0 +1,219 @@ +UserID = $UserID; + if($Options['visible'] === false){ + $this->Visible = false; + } + } + + function make_tree(){ + $UserID = $this->UserID; + global $DB; +?> +
    +query("SELECT + t1.TreePosition, + t1.TreeID, + t1.TreeLevel, + (SELECT + t2.TreePosition FROM invite_tree AS t2 + WHERE TreeID=t1.TreeID AND TreeLevel=t1.TreeLevel AND t2.TreePosition>t1.TreePosition + ORDER BY TreePosition LIMIT 1 + ) AS MaxPosition + FROM invite_tree AS t1 + WHERE t1.UserID=$UserID"); + + list($TreePosition, $TreeID, $TreeLevel, $MaxPosition) = $DB->next_record(); + if(!$MaxPosition){ $MaxPosition = 1000000; } // $MaxPermission is null if the user is the last one in that tree on that level + if(!$TreeID){ return; } + $TreeQuery = $DB->query(" + SELECT + it.UserID, + Username, + Donor, + Warned, + Enabled, + PermissionID, + Uploaded, + Downloaded, + Paranoia, + TreePosition, + TreeLevel + FROM invite_tree AS it + JOIN users_main AS um ON um.ID=it.UserID + JOIN users_info AS ui ON ui.UserID=it.UserID + WHERE TreeID=$TreeID + AND TreePosition>$TreePosition + AND TreePosition<$MaxPosition + AND TreeLevel>$TreeLevel + ORDER BY TreePosition"); + + $PreviousTreeLevel = $TreeLevel; + + // Stats for the summary + $MaxTreeLevel = $TreeLevel; // The deepest level (this changes) + $OriginalTreeLevel = $TreeLevel; // The level of the user we're viewing + $BaseTreeLevel = $TreeLevel + 1; // The level of users invited by our user + $Count = 0; + $Branches = 0; + $DisabledCount = 0; + $DonorCount = 0; + $ParanoidCount = 0; + $TotalUpload = 0; + $TotalDownload = 0; + $TopLevelUpload = 0; + $TopLevelDownload = 0; + + $ClassSummary = array(); + global $Classes; + foreach ($Classes as $ClassID => $Val) { + $ClassSummary[$ClassID] = 0; + } + + // We store this in an output buffer, so we can show the summary at the top without having to loop through twice + ob_start(); + while(list($ID, $Username, $Donor, $Warned, $Enabled, $Class, $Uploaded, $Downloaded, $Paranoia, $TreePosition, $TreeLevel) = $DB->next_record()){ + + // Do stats + $Count++; + + if($TreeLevel > $MaxTreeLevel){ + $MaxTreeLevel = $TreeLevel; + } + + if($TreeLevel == $BaseTreeLevel){ + $Branches++; + $TopLevelUpload += $Uploaded; + $TopLevelDownload += $Downloaded; + } + + $ClassSummary[$Class]++; + if($Enabled == 2){ + $DisabledCount++; + } + if($Donor){ + $DonorCount++; + } + + // Manage tree depth + if($TreeLevel > $PreviousTreeLevel){ + for($i = 0; $i<$TreeLevel-$PreviousTreeLevel; $i++){ echo "
      \n"; } + } elseif($TreeLevel < $PreviousTreeLevel){ + for($i = 0; $i<$PreviousTreeLevel-$TreeLevel; $i++){ echo "
    \n"; } + } +?> +
  1. + + +  Uploaded: +  Downloaded: +  Ratio: + +  Paranoia: + +
  2. +set_query_id($TreeQuery); + } + $Tree = ob_get_clean(); + if($Count){ + +?>

    + This tree has entries, branches, and a depth of . + It has + $ClassCount) { + if($ClassCount == 0) { continue; } + $LastClass = make_class_string($ClassID); + if($ClassCount>1) { + if($LastClass == "Torrent Celebrity") { + $LastClass = 'Torrent Celebrities'; + } else { + $LastClass.='s'; + } + } + $LastClass= $ClassCount.' '.$LastClass.' (' . number_format(($ClassCount/$Count)*100) . '%)'; + + $ClassStrings []= $LastClass; + } + if(count($ClassStrings)>1){ + array_pop($ClassStrings); + echo implode(', ', $ClassStrings); + echo ' and '.$LastClass; + } else { + echo $LastClass; + } + echo '. '; + echo $DisabledCount; + echo ($DisabledCount==1)?' user is':' users are'; + echo ' disabled ('; + if($DisabledCount == 0) { echo '0%)'; } + else { echo number_format(($DisabledCount/$Count)*100) . '%)';} + echo ', and '; + echo $DonorCount; + echo ($DonorCount==1)?' user has':' users have'; + echo ' donated ('; + if($DonorCount == 0) { echo '0%)'; } + else { echo number_format(($DonorCount/$Count)*100) . '%)';} + echo '.

    '; + + echo '

    '; + echo 'The total amount uploaded by the entire tree was '.get_size($TotalUpload); + echo ', the total amount downloaded was '.get_size($TotalDownload); + echo ', and the total ratio is '.ratio($TotalUpload, $TotalDownload).'. '; + echo '

    '; + + echo '

    '; + echo 'The total amount uploaded by direct invitees (the top level) was '.get_size($TopLevelUpload); + echo ', the total amount downloaded was '.get_size($TopLevelDownload); + echo ', and the total ratio is '.ratio($TopLevelUpload, $TopLevelDownload).'. '; + + + echo 'These numbers include the stats of paranoid users, and will be factored in to the invitation giving script.

    '; + + + if($ParanoidCount){ + echo '

    '; + echo $ParanoidCount; + echo ($ParanoidCount==1)?' user (':' users ('; + echo number_format(($ParanoidCount/$Count)*100); + echo '%) '; + echo ($ParanoidCount==1)?' is':' are'; + echo ' too paranoid to have their stats shown here, and '; + echo ($ParanoidCount==1)?' was':' were'; + echo ' not factored into the stats for the total tree.'; + echo '

    '; + } + } + +?> +
    + +
    + diff --git a/classes/class_irc.php b/classes/class_irc.php new file mode 100644 index 00000000..5ebe9d5b --- /dev/null +++ b/classes/class_irc.php @@ -0,0 +1,194 @@ +send_to($Bot->get_channel(),'The database is currently unavailable try again later'); + } +} + +abstract class IRC_BOT { + abstract protected function connect_events(); + abstract protected function channel_events(); + abstract protected function query_events(); + abstract protected function listener_events(); + + protected $Debug = false; + protected $Socket = false; + protected $Data = false; + protected $Whois = false; + protected $Identified = array(); + protected $Channels = array(); + protected $Messages = array(); + protected $LastChan = false; + protected $ListenSocket =false; + protected $Listened = false; + protected $State = 1; //Drones live + public $Restart = 0; //Die by default + + public function __construct() { + //ini_set('memory_limit', '12M'); + restore_error_handler(); //Avoid PHP error logging + set_time_limit(0); + } + + public function connect() { + //Open a socket to the IRC server + $this->Socket = fsockopen(BOT_SERVER, BOT_PORT); + stream_set_blocking($this->Socket, 0); + + //create a socket to listen on + $this->ListenSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + //socket_set_option($this->ListenSocket, SOL_TCP, SO_REUSEADDR, 1); + socket_set_option($this->ListenSocket, SOL_SOCKET, SO_REUSEADDR, 1); + socket_bind($this->ListenSocket, SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT); + socket_listen($this->ListenSocket); + socket_set_nonblock($this->ListenSocket); + + $this->Debug = $Debug; + fwrite($this->Socket, "NICK ".BOT_NICK."Init\n"); + fwrite($this->Socket, "USER ".BOT_NICK." * * :IRC Bot\n"); + $this->listen(); + } + + public function disconnect() { + socket_close($this->ListenSocket); + $this->State = 0; //Drones dead + } + + public function get_channel() { + preg_match('/.+ PRIVMSG ([^:]+) :.+/', $this->Data, $Channel); + if(preg_match('/#.+/',$Channel[1])) { + return $Channel[1]; + } else { + return false; + } + } + + public function get_nick() { + preg_match('/:([^!:]+)!.+@[^\s]+ PRIVMSG [^:]+ :.+/', $this->Data, $Nick); + return $Nick[1]; + } + + protected function get_message() { + preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Msg); + return trim($Msg[1]); + } + + protected function get_host() { + preg_match('/:[^!:]+!.+@([^\s]+) PRIVMSG [^:]+ :.+/', $this->Data, $Host); + return trim($Host[1]); + } + + protected function get_word($Select=1) { + preg_match('/:.+ PRIVMSG [^:]+ :(.+)/', $this->Data, $Word); + $Word = split(' ',$Word[1]); + return trim($Word[$Select]); + } + + protected function get_action() { + preg_match('/:.+ PRIVMSG [^:]+ :!(\S+)/', $this->Data, $Action); + return strtoupper($Action[1]); + } + + protected function send_raw($Text) { + fwrite($this->Socket, $Text."\n"); + } + + public function send_to($Channel, $Text) { + fwrite($this->Socket, "PRIVMSG $Channel :$Text\n"); + } + + protected function whois($Nick) { + $this->Whois = $Nick; + $this->send_raw("WHOIS $Nick"); + } + + /* + This function uses blacklisted_ip, which is no longer in RC2. + You can probably find it in old RC1 code kicking aronud if you need it. + protected function ip_check($IP,$Gline=false,$Channel=BOT_REPORT_CHAN) { + global $Cache, $DB; + if(blacklisted_ip($IP)) { + $this->send_to($Channel, 'TOR IP Detected: '.$IP); + if ($Gline) { + $this->send_raw('GLINE *@'.$IP.' 90d :DNSBL Proxy'); + } + } + $IPBans = $Cache->get_value('ip_bans'); + if(!is_array($IPBans)) { + $DB->query("SELECT FromIP, ToIP FROM ip_bans"); + $IPBans = $DB->to_array(); + $Cache->cache_value('ip_bans', $IPBans, 0); + } + foreach($IPBans as $IPBan) { + list($FromIP, $ToIP) = $IPBan; + $Long = ip2long($IP); + if($Long >= $FromIP && $Long <= $ToIP) { + $this->send_to($Channel, 'Site IP Ban Detected: '.$IP); + if ($Gline) { + $this->send_raw('GLINE *@'.$IP.' 90d :IP Ban'); + } + } + } + }*/ + + protected function listen() { + global $Cache,$DB; + stream_set_timeout($this->Socket, 10000000000); + while($this->State == 1){ + if($this->Data = fgets($this->Socket, 256)) { + //IP checks + //if(preg_match('/:\*\*\* (?:REMOTE)?CONNECT: Client connecting (?:.*) \[(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\] \[(.+)\]/', $this->Data, $IP)) { + // $this->ip_check($IP[1],true); + //} + + if($this->Debug === true) { + $this->send_to(BOT_DEBUG_CHAN, $this->Data); + } + + if($this->Whois !== false) { + $Exp = explode(' ',$this->Data); + if($Exp[1] == '307') { + $this->Identified[$this->Whois] = 1; + $this->send_to($this->LastChan, "$this->Whois correctly identified as a real person!"); + $this->Whois = false; + $this->LastChan = false; + } elseif($Exp[6] == '/WHOIS') { + $this->Whois = false; + } + } + + if(preg_match("/:([^!]+)![^\s]* QUIT.* /", $this->Data, $Nick)) { + if(isset($this->Identified[$Nick[1]])) { + unset($this->Identified[$Nick[1]]); + } + } + + if(preg_match("/End of message of the day./", $this->Data)) { + $this->connect_events(); + } + + if(preg_match('/PING :(.+)/', $this->Data, $Ping)) { + $this->send_raw('PONG :'.$Ping[1]); + } + + if(preg_match('/.*PRIVMSG #.*/',$this->Data)) { + $this->channel_events(); + } + + if(preg_match("/.* PRIVMSG ".BOT_NICK." .*/",$this->Data)) { + $this->query_events(); + } + } + + if($this->Listened = @socket_accept($this->ListenSocket)) { + $this->listener_events(); + } + + $DB->LinkID = false; + $DB->Queries = array(); + usleep(5000); + } + } +} +?> diff --git a/classes/class_mysql.php b/classes/class_mysql.php new file mode 100644 index 00000000..99ebd259 --- /dev/null +++ b/classes/class_mysql.php @@ -0,0 +1,338 @@ +query("SELECT * FROM table..."); + Is functionally equivalent to using mysqli_query("SELECT * FROM table...") + Stores the result set in $this->QueryID + Returns the result set, so you can save it for later (see set_query_id()) +----- + +* Getting data from a query + +$array = $DB->next_record(); + Is functionally equivalent to using mysqli_fetch_array($ResultSet) + You do not need to specify a result set - it uses $this-QueryID +----- + +* Escaping a string + +db_string($str); + Is a wrapper for $DB->escape_str(), which is a wrapper for + mysqli_real_escape_string(). The db_string() function exists so that you + don't have to keep calling $DB->escape_str(). + + USE THIS FUNCTION EVERY TIME YOU USE AN UNVALIDATED USER-SUPPLIED VALUE IN + A DATABASE QUERY! + + +//--------- Advanced usage --------------------------------------------------------- + +* The conventional way of retrieving a row from a result set is as follows: + +list($All,$Columns,$That,$You,$Select)=$DB->next_record(); +----- + +* This is how you loop over the result set: + +while(list($All,$Columns,$That,$You,$Select)=$DB->next_record()){ + echo "Do stuff with ".$All." of the ".$Columns.$That.$You.$Select; +} +----- + +* There are also a couple more mysqli functions that have been wrapped. They are: + +record_count() + Wrapper to mysqli_num_rows() + +affected_rows() + Wrapper to mysqli_affected_rows() + +inserted_id() + Wrapper to mysqli_insert_id() + +close + Wrapper to mysqli_close() +----- + +* And, of course, a few handy custom functions. + +to_array($Key = false) + Transforms an entire result set into an array (useful in situations where you + can't order the rows properly in the query). + + If $Key is set, the function uses $Key as the index (good for looking up a + field). Otherwise, it uses an iterator. + + For an example of this function in action, check out forum.php. + +collect($Key) + Loops over the result set, creating an array from one of the fields ($Key). + For an example, see forum.php. + +set_query_id($ResultSet) + This class can only hold one result set at a time. Using set_query_id allows + you to set the result set that the class is using to the result set in + $ResultSet. This result set should have been obtained earlier by using + $DB-query(). + + Example: + + $FoodRS = $DB->query("SELECT * FROM food"); + $DB->query("SELECT * FROM drink"); + $Drinks = $DB->next_record(); + $DB->set_query_id($FoodRS); + $Food = $DB->next_record(); + + Of course, this example is contrived, but you get the point. + + +------------------------------------------------------------------------------------- +*///--------------------------------------------------------------------------------- + +if (!extension_loaded('mysqli')) { + error('Mysqli Extension not loaded.'); +} + +//Handles escaping +function db_string($String,$DisableWildcards=false) { + global $DB; + //Escape + $String = $DB->escape_str($String); + //Remove user input wildcards + if ($DisableWildcards) { + $String = str_replace(array('%','_'), array('\%','\_'), $String); + } + return $String; +} + +function db_array($Array, $DontEscape = array(), $Quote = false) { + foreach ($Array as $Key => $Val) { + if(!in_array($Key, $DontEscape)) { + if($Quote) { + $Array[$Key] = '\''.db_string(trim($Val)).'\''; + } else { + $Array[$Key] = db_string(trim($Val)); + } + } + } + return $Array; +} + +//TODO: revisit access levels once Drone is replaced by ZeRobot +class DB_MYSQL { + public $LinkID = false; + protected $QueryID = false; + protected $Record = array(); + protected $Row; + protected $Errno = 0; + protected $Error = ''; + + public $Queries = array(); + public $Time = 0.0; + + protected $Database = ''; + protected $Server = ''; + protected $User = ''; + protected $Pass = ''; + protected $Port = 0; + protected $Socket = ''; + + function __construct($Database = SQLDB, $User = SQLLOGIN, $Pass = SQLPASS, $Server = SQLHOST, $Port = SQLPORT, $Socket = SQLSOCK) { + $this->Database = $Database; + $this->Server = $Server; + $this->User = $User; + $this->Pass = $Pass; + $this->Port = $Port; + $this->Socket = $Socket; + } + + function halt($Msg) { + global $LoggedUser, $Cache, $Debug, $argv; + $DBError='MySQL: '.strval($Msg).' SQL error: '.strval($this->Errno).' ('.strval($this->Error).')'; + if ($this->Errno == 1194) { send_irc('PRIVMSG '.ADMIN_CHAN.' :'.$this->Error); } + /*if ($this->Errno == 1194) { + preg_match("Table '(\S+)' is marked as crashed and should be repaired", $this->Error, $Matches); + } */ + $Debug->analysis('!dev DB Error',$DBError,3600*24); + if (DEBUG_MODE || check_perms('site_debug') || isset($argv[1])) { + echo '
    '.display_str($DBError).'
    '; + if(DEBUG_MODE || check_perms('site_debug')) { + print_r($this->Queries); + } + die(); + } else { + error('-1'); + } + } + + function connect() { + if(!$this->LinkID) { + $this->LinkID = mysqli_connect($this->Server, $this->User, $this->Pass, $this->Database, $this->Port, $this->Socket); // defined in config.php + if (!$this->LinkID) { + $this->Errno = mysqli_connect_errno(); + $this->Error = mysqli_connect_error(); + $this->halt('Connection failed (host:'.$this->Server.':'.$this->Port.')'); + } + } + } + + function query($Query,$AutoHandle=1) { + global $LoggedUser, $Debug; + $QueryStartTime=microtime(true); + $this->connect(); + //In the event of a mysql deadlock, we sleep allowing mysql time to unlock then attempt again for a maximum of 5 tries + for($i=1; $i<6; $i++) { + $this->QueryID = mysqli_query($this->LinkID,$Query); + if(!in_array(mysqli_errno($this->LinkID), array(1213, 1205))) { + break; + } + $Debug->analysis('Non-Fatal Deadlock:',$Query,3600*24); + trigger_error("Database deadlock, attempt $i"); + + sleep($i*rand(2, 5)); // Wait longer as attempts increase + } + $QueryEndTime=microtime(true); + $this->Queries[]=array(display_str($Query),($QueryEndTime-$QueryStartTime)*1000); + $this->Time+=($QueryEndTime-$QueryStartTime)*1000; + + if (!$this->QueryID) { + $this->Errno = mysqli_errno($this->LinkID); + $this->Error = mysqli_error($this->LinkID); + + if ($AutoHandle) { + $this->halt('Invalid Query: '.$Query); + } else { + return $this->Errno; + } + } + + $QueryType = substr($Query,0, 6); + /* + if ($QueryType == 'DELETE' || $QueryType == 'UPDATE') { + if ($this->affected_rows() > 50) { + $Debug->analysis($this->affected_rows().' rows altered:',$Query,3600*24); + } + } + */ + $this->Row = 0; + if ($AutoHandle) { return $this->QueryID; } + } + + function query_unb($Query) { + $this->connect(); + mysqli_real_query($this->LinkID,$Query); + } + + function inserted_id() { + if($this->LinkID) { + return mysqli_insert_id($this->LinkID); + } + } + + function next_record($Type=MYSQLI_BOTH, $Escape = true) { // $Escape can be true, false, or an array of keys to not escape + if($this->LinkID) { + $this->Record = mysqli_fetch_array($this->QueryID,$Type); + $this->Row++; + if (!is_array($this->Record)) { + $this->QueryID = FALSE; + } elseif($Escape !== FALSE){ + $this->Record = display_array($this->Record, $Escape); + } + return $this->Record; + } + } + + function close() { + if($this->LinkID) { + if(!mysqli_close($this->LinkID)) { + $this->halt('Cannot close connection or connection did not open.'); + } + $this->LinkID = FALSE; + } + } + + function record_count() { + if ($this->QueryID) { + return mysqli_num_rows($this->QueryID); + } + } + + function affected_rows() { + if($this->LinkID) { + return mysqli_affected_rows($this->LinkID); + } + } + + function info() { + return mysqli_get_host_info($this->LinkID); + } + + // You should use db_string() instead. + function escape_str($Str) { + $this->connect(0); + if (is_array($Str)) { + trigger_error('Attempted to escape array.'); + return ''; + } + return mysqli_real_escape_string($this->LinkID,$Str); + } + + // Creates an array from a result set + // If $Key is set, use the $Key column in the result set as the array key + // Otherwise, use an integer + function to_array($Key = false, $Type = MYSQLI_BOTH, $Escape = true) { + $Return = array(); + while($Row = mysqli_fetch_array($this->QueryID,$Type)){ + if($Escape!==FALSE) { + $Row = display_array($Row, $Escape); + } + if($Key !== false) { + $Return[$Row[$Key]] = $Row; + } else { + $Return[]=$Row; + } + } + mysqli_data_seek($this->QueryID, 0); + return $Return; + } + + // Loops through the result set, collecting the $Key column into an array + function collect($Key, $Escape = true) { + $Return = array(); + while($Row = mysqli_fetch_array($this->QueryID)){ + $Return[] = $Escape ? display_str($Row[$Key]) : $Row[$Key]; + } + mysqli_data_seek($this->QueryID, 0); + return $Return; + } + + function set_query_id(&$ResultSet){ + $this->QueryID = $ResultSet; + $this->Row = 0; + } + + function beginning() { + mysqli_data_seek($this->QueryID, 0); + } + +} +?> diff --git a/classes/class_paranoia.php b/classes/class_paranoia.php new file mode 100644 index 00000000..aeb37d40 --- /dev/null +++ b/classes/class_paranoia.php @@ -0,0 +1,88 @@ +SetServer(SPHINX_HOST, SPHINX_PORT); + $this->SetMatchMode(SPH_MATCH_EXTENDED2); + } + + /**************************************************************** + /--- Search function -------------------------------------------- + + This function queries sphinx for whatever is in $Query, in + extended2 mode. It then fetches the records for each primary key + from memcached (by joining $CachePrefix and the primary key), and + fetches the fields needed ($ReturnData) from the memcached + result. + + Any keys not found in memcached are then queried in MySQL, using + $SQL. They are then cached, and merged with the memcached matches + and returned. + + $Query - sphinx query + $CachePrefix - Prefix for memcache key (no underscore) + $CacheLength - How long to store data in the cache, if it's found by MySQL + $ReturnData - Array of keys to the array in memcached to return. + If empty, return all. + $SQL - SQL query to fetch results not found in memcached + - Should take the format of: + SELECT fields FROM table WHERE primary key IN(%ids) + where %ids will be replaced by a list of IDs not found in memcached + $IDColumn - The primary key of the SQL table - must be the + same primary key returned by sphinx! + + ****************************************************************/ + + function search($Query='', $CachePrefix='', $CacheLength=0, $ReturnData=array(), $SQL = '', $IDColumn='ID') { + global $Cache, $DB; + $QueryStartTime=microtime(true); + $Result = $this->Query($Query, $this->Index); + $QueryEndTime=microtime(true); + + $Filters = array(); + foreach($this->Filters as $Name => $Values) { + foreach($Values as $Value) { + $Filters[] = $Name." - ".$Value; + } + } + + $this->Queries[]=array('Params: '.$Query.' Filters: '.implode(", ", $Filters).' Indicies: '.$this->Index,($QueryEndTime-$QueryStartTime)*1000); + $this->Time+=($QueryEndTime-$QueryStartTime)*1000; + + if($Result === false) { + if($this->_connerror && !$Cache->get_value('sphinx_crash_reported')) { + send_irc('PRIVMSG '.ADMIN_CHAN.' :!dev Connection to searchd failed'); + $Cache->cache_value('sphinx_crash_reported', 1, 3600); + } + send_irc('PRIVMSG '.LAB_CHAN.' :Search for "'.$Query.'" ('.str_replace("\n",'',print_r($this->Filters, true)).') failed: '.$this->GetLastError()); + } + + $this->TotalResults = $Result['total']; + $this->SearchTime = $Result['time']; + + if(empty($Result['matches'])) { + return false; + } + $Matches = $Result['matches']; + + $MatchIDs = array_keys($Matches); + + + + $NotFound = array(); + $Skip = array(); + if(!empty($ReturnData)) { + $AllFields = false; + } else { + $AllFields = true; + } + + foreach($MatchIDs as $Match) { + $Matches[$Match] = $Matches[$Match]['attrs']; + if(!empty($CachePrefix)) { + $Data = $Cache->get_value($CachePrefix.'_'.$Match); + if($Data == false) { + $NotFound[]=$Match; + continue; + } + } else { + $NotFound[]=$Match; + } + if(!$AllFields) { + // Populate list of fields to unset (faster than picking out the ones we need). Should only be run once, on the first cache key + if(empty($Skip)) { + foreach(array_keys($Data) as $Key) { + if(!in_array($Key, $ReturnData)) { + $Skip[]=$Key; + } + } + if(empty($Skip)) { + $AllFields = true; + } + } + foreach($Skip as $Key) { + unset($Data[$Key]); + } + reset($Skip); + } + if(!empty($Data)) { + $Matches[$Match] = array_merge($Matches[$Match], $Data); + } + } + + if($SQL!='') { + if(!empty($NotFound)) { + $DB->query(str_replace('%ids', implode(',',$NotFound), $SQL)); + while($Data = $DB->next_record(MYSQLI_ASSOC)) { + $Matches[$Data[$IDColumn]] = array_merge($Matches[$Data[$IDColumn]], $Data); + $Cache->cache_value($CachePrefix.'_'.$Data[$IDColumn], $Data, $CacheLength); + } + } + } else { + $Matches = array('matches'=>$Matches,'notfound'=>$NotFound); + } + + return $Matches; + } + + function limit($Start, $Length, $MaxMatches=SPHINX_MATCHES_START) { + if(check_perms('site_search_many') && empty($_GET['limit_matches'])) { + $MaxMatches = 500000; + } + $this->SetLimits((int)$Start, (int)$Length, $MaxMatches, 0); + } + + + function set_index($Index) { + $this->Index = $Index; + } + + function set_filter($Name, $Vals, $Exclude=false) { + foreach($Vals as $Val) { + $this->Filters[$Name][] = $Val; + } + $this->SetFilter($Name, $Vals, $Exclude); + } + + function set_filter_range($Name, $Min, $Max, $Exclude) { + $this->Filters[$Name] = array($Min.'-'.$Max); + $this->SetFilterRange($Name, $Min, $Max, $Exclude); + } + + function escape_string($String) { + return strtr($String, array('('=>'\(', ')'=>'\)', '|'=>'\|', '-'=>'\-', '@'=>'\@', '~'=>'\~', '&'=>'\&', '/'=>'\/')); + } + + +} +?> diff --git a/classes/class_templates.php b/classes/class_templates.php new file mode 100644 index 00000000..30ee5c4f --- /dev/null +++ b/classes/class_templates.php @@ -0,0 +1,81 @@ +open('inv.tpl'); +// $TPL->set('ADDRESS1',$TPL->str_align(57,$UADDRESS1,'l',' ')); +// $TPL->get(); + +class TEMPLATE { + var $file=''; + var $vars=array(); + + function open($file) { + $this->file=file($file); + } + + function set($name,$var,$ifnone="-None-") { + if ($name!='') { + $this->vars[$name][0]=$var; + $this->vars[$name][1]=$ifnone; + } + } + + function show() { + $TMPVAR=''; + for($i=0; $ifile); $i++) { + $TMPVAR=$this->file[$i]; + foreach($this->vars as $k=>$v) { + if ($v[1]!="" && $v[0]=="") { $v[0]=$v[1]; } + $TMPVAR=str_replace('{{'.$k.'}}',$v[0],$TMPVAR); + } + print $TMPVAR; + } + } + + function get() { + $RESULT=''; + $TMPVAR=''; + for($i=0; $ifile); $i++) { + $TMPVAR=$this->file[$i]; + foreach($this->vars as $k=>$v) { + if ($v[1]!="" && $v[0]=="") { $v[0]=$v[1]; } + $TMPVAR=str_replace('{{'.$k.'}}',$v[0],$TMPVAR); + } + $RESULT.=$TMPVAR; + } + return $RESULT; + } + + function str_align($len,$str,$align,$fill) { + $strlen=strlen($str); + if ($strlen>$len) { + return substr($str, 0, $len); + + } elseif (($strlen==0)||($len==0)) { + return ''; + + } else { + if (($align=='l')||($align=='left')) { + $result=$str.str_repeat($fill,($len-$strlen)); + + } elseif (($align=='r')||($align=='right')) { + $result=str_repeat($fill,($len-$strlen)).$str; + + } elseif (($align=='c')||($align=='center')) { + $snm=intval(($len-$strlen)/2); + if (($strlen+($snm*2))==$len) { + $result=str_repeat($fill,$snm).$str; + + } else { + $result=str_repeat($fill,$snm+1).$str; + + } + + $result.=str_repeat($fill,$snm); + } + + return $result; + } + } +} +?> diff --git a/classes/class_text.php b/classes/class_text.php new file mode 100644 index 00000000..78c85111 --- /dev/null +++ b/classes/class_text.php @@ -0,0 +1,702 @@ +max number of attributes + private $ValidTags = array('b'=>0, 'u'=>0, 'i'=>0, 's'=>0, '*'=>0, '#'=>0, 'artist'=>0, 'user'=>0, 'n'=>0, 'inlineurl'=>0, 'inlinesize'=>1, 'align'=>1, 'color'=>1, 'colour'=>1, 'size'=>1, 'url'=>1, 'img'=>1, 'quote'=>1, 'pre'=>1, 'code'=>1, 'tex'=>0, 'hide'=>1, 'plain'=>0, 'important'=>0, 'torrent'=>0 + ); + private $Smileys = array( + ':angry:' => 'angry.gif', + ':-D' => 'biggrin.gif', + ':D' => 'biggrin.gif', + ':|' => 'blank.gif', + ':-|' => 'blank.gif', + ':blush:' => 'blush.gif', + ':cool:' => 'cool.gif', + ':'(' => 'crying.gif', + ':crying:' => 'crying.gif', + '>.>' => 'eyesright.gif', + ':frown:' => 'frown.gif', + '<3' => 'heart.gif', + ':unsure:' => 'hmm.gif', + ':\\' => 'hmm.gif', + ':whatlove:' => 'ilu.gif', + ':lol:' => 'laughing.gif', + ':loveflac:' => 'loveflac.gif', + ':ninja:' => 'ninja.gif', + ':no:' => 'no.gif', + ':nod:' => 'nod.gif', + ':ohno:' => 'ohnoes.gif', + ':ohnoes:' => 'ohnoes.gif', + ':omg:' => 'omg.gif', + ':o' => 'ohshit.gif', + ':O' => 'ohshit.gif', + ':paddle:' => 'paddle.gif', + ':(' => 'sad.gif', + ':-(' => 'sad.gif', + ':shifty:' => 'shifty.gif', + ':sick:' => 'sick.gif', + ':)' => 'smile.gif', + ':-)' => 'smile.gif', + ':sorry:' => 'sorry.gif', + ':thanks:' => 'thanks.gif', + ':P' => 'tongue.gif', + ':-P' => 'tongue.gif', + ':-p' => 'tongue.gif', + ':wave:' => 'wave.gif', + ';-)' => 'wink.gif', + ':wink:' => 'wink.gif', + ':creepy:' => 'creepy.gif', + ':worried:' => 'worried.gif', + ':wtf:' => 'wtf.gif', + ':wub:' => 'wub.gif', + ); + + private $NoImg = 0; // If images should be turned into URLs + private $Levels = 0; // If images should be turned into URLs + + function __construct() { + foreach($this->Smileys as $Key=>$Val) { + $this->Smileys[$Key] = ''; + } + reset($this->Smileys); + } + + function full_format($Str) { + $Str = display_str($Str); + + //Inline links + $URLPrefix = '(\[url\]|\[url\=|\[img\=|\[img\])'; + $Str = preg_replace('/'.$URLPrefix.'\s+/i', '$1', $Str); + $Str = preg_replace('/(?parse($Str); + + $HTML = $this->to_html($Str); + + $HTML = nl2br($HTML); + return $HTML; + } + + function strip_bbcode($Str) { + $Str = display_str($Str); + + //Inline links + $Str = preg_replace('/(?parse($Str); + + $Str = $this->raw_text($Str); + + $Str = nl2br($Str); + return $Str; + } + + + function valid_url($Str, $Extension = '', $Inline = false) { + $Regex = '/^'; + $Regex .= '(https?|ftps?|irc):\/\/'; // protocol + $Regex .= '(\w+(:\w+)?@)?'; // user:pass@ + $Regex .= '('; + $Regex .= '(([0-9]{1,3}\.){3}[0-9]{1,3})|'; // IP or... + $Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})'; // sub.sub.sub.host.com + $Regex .= ')'; + $Regex .= '(:[0-9]{1,5})?'; // port + $Regex .= '\/?'; // slash? + $Regex .= '(\/?[0-9a-z\-_.,&=@~%\/:;()+|!#]+)*'; // /file + if(!empty($Extension)) { + $Regex.=$Extension; + } + + // query string + if ($Inline) { + $Regex .= '(\?([0-9a-z\-_.,%\/\@~&=:;()+*\^$!#|]|\[\d*\])*)?'; + } else { + $Regex .= '(\?[0-9a-z\-_.,%\/\@[\]~&=:;()+*\^$!#|]*)?'; + } + + $Regex .= '(#[a-z0-9\-_.,%\/\@[\]~&=:;()+*\^$!]*)?'; // #anchor + $Regex .= '$/i'; + + return preg_match($Regex, $Str, $Matches); + } + + function local_url($Str) { + $URLInfo = parse_url($Str); + if(!$URLInfo) { return false; } + $Host = $URLInfo['host']; + // If for some reason your site does not require subdomains or contains a directory in the SITE_URL, revert to the line below. + //if($Host == NONSSL_SITE_URL || $Host == SSL_SITE_URL || $Host == 'www.'.NONSSL_SITE_URL) { + if(preg_match('/(\S+\.)*'.NONSSL_SITE_URL.'/', $Host)) { + $URL = $URLInfo['path']; + if(!empty($URLInfo['query'])) { + $URL.='?'.$URLInfo['query']; + } + if(!empty($URLInfo['fragment'])) { + $URL.='#'.$URLInfo['fragment']; + } + return $URL; + } else { + return false; + } + + } + + +/* How parsing works + +Parsing takes $Str, breaks it into blocks, and builds it into $Array. +Blocks start at the beginning of $Str, when the parser encounters a [, and after a tag has been closed. +This is all done in a loop. + +EXPLANATION OF PARSER LOGIC + +1) Find the next tag (regex) + 1a) If there aren't any tags left, write everything remaining to a block and return (done parsing) + 1b) If the next tag isn't where the pointer is, write everything up to there to a text block. +2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name +3) If it's not a wiki link: + 3a) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit] + If it's [not a tag], just leave it as plaintext and move on + 3b) Get the attribute, if it exists [name=attribute] +4) Move the pointer past the end of the tag +5) Find out where the tag closes (beginning of [/tag]) + 5a) Different for different types of tag. Some tags don't close, others are weird like [*] + 5b) If it's a normal tag, it may have versions of itself nested inside - eg: + [quote=bob]* + [quote=joe]I am a redneck!**[/quote] + Me too! + ***[/quote] + If we're at the position *, the first [/quote] tag is denoted by **. + However, our quote tag doesn't actually close there. We must perform + a loop which checks the number of opening [quote] tags, and make sure + they are all closed before we find our final [/quote] tag (***). + + 5c) Get the contents between [open] and [/close] and call it the block. + In many cases, this will be parsed itself later on, in a new parse() call. + 5d) Move the pointer past the end of the [/close] tag. +6) Depending on what type of tag we're dealing with, create an array with the attribute and block. + In many cases, the block may be parsed here itself. Stick them in the $Array. +7) Increment array pointer, start again (past the end of the [/close] tag) + +*/ + function parse($Str) { + $i = 0; // Pointer to keep track of where we are in $Str + $Len = strlen($Str); + $Array = array(); + $ArrayPos = 0; + + while($i<$Len) { + $Block = ''; + + // 1) Find the next tag (regex) + // [name(=attribute)?]|[[wiki-link]] + $IsTag = preg_match("/((\[[a-zA-Z*#]+)(=(?:[^\n'\"\[\]]|\[\d*\])+)?\])|(\[\[[^\n\"'\[\]]+\]\])/", $Str, $Tag, PREG_OFFSET_CAPTURE, $i); + + // 1a) If there aren't any tags left, write everything remaining to a block + if(!$IsTag) { + // No more tags + $Array[$ArrayPos] = substr($Str, $i); + break; + } + + // 1b) If the next tag isn't where the pointer is, write everything up to there to a text block. + $TagPos = $Tag[0][1]; + if($TagPos>$i) { + $Array[$ArrayPos] = substr($Str, $i, $TagPos-$i); + ++$ArrayPos; + $i=$TagPos; + } + + // 2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name + if(!empty($Tag[4][0])) { // Wiki-link + $WikiLink = true; + $TagName = substr($Tag[4][0], 2, -2); + $Attrib = ''; + } else { // 3) If it's not a wiki link: + $WikiLink = false; + $TagName = strtolower(substr($Tag[2][0], 1)); + + //3a) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit] + if(!isset($this->ValidTags[$TagName])) { + $Array[$ArrayPos] = substr($Str, $i, ($TagPos-$i)+strlen($Tag[0][0])); + $i=$TagPos+strlen($Tag[0][0]); + ++$ArrayPos; + continue; + } + + $MaxAttribs = $this->ValidTags[$TagName]; + + // 3b) Get the attribute, if it exists [name=attribute] + if(!empty($Tag[3][0])) { + $Attrib = substr($Tag[3][0], 1); + } else { + $Attrib=''; + } + } + + // 4) Move the pointer past the end of the tag + $i=$TagPos+strlen($Tag[0][0]); + + // 5) Find out where the tag closes (beginning of [/tag]) + + // Unfortunately, BBCode doesn't have nice standards like xhtml + // [*], [img=...], and http:// follow different formats + // Thus, we have to handle these before we handle the majority of tags + + + //5a) Different for different types of tag. Some tags don't close, others are weird like [*] + if($TagName == 'img' && !empty($Tag[3][0])) { //[img=...] + $Block = ''; // Nothing inside this tag + // Don't need to touch $i + } elseif($TagName == 'inlineurl') { // We did a big replace early on to turn http:// into [inlineurl]http:// + + // Let's say the block can stop at a newline or a space + $CloseTag = strcspn($Str, " \n\r", $i); + if($CloseTag === false) { // block finishes with URL + $CloseTag = $Len; + } + if(preg_match('/[!;,.?:]+$/',substr($Str, $i, $CloseTag), $Match)) { + $CloseTag -= strlen($Match[0]); + } + $URL = substr($Str, $i, $CloseTag); + if(substr($URL, -1) == ')' && substr_count($URL, '(') < substr_count($URL, ')')) { + $CloseTag--; + $URL = substr($URL, 0, -1); + } + $Block = $URL; // Get the URL + + // strcspn returns the number of characters after the offset $i, not after the beginning of the string + // Therefore, we use += instead of the = everywhere else + $i += $CloseTag; // 5d) Move the pointer past the end of the [/close] tag. + } elseif($WikiLink == true || $TagName == 'n') { + // Don't need to do anything - empty tag with no closing + } elseif($TagName === '*' || $TagName === '#') { + // We're in a list. Find where it ends + $NewLine = $i; + do { // Look for \n[*] + $NewLine = strpos($Str, "\n", $NewLine+1); + } while($NewLine!== false && substr($Str, $NewLine+1, 3) == '['.$TagName.']'); + + $CloseTag = $NewLine; + if($CloseTag === false) { // block finishes with list + $CloseTag = $Len; + } + $Block = substr($Str, $i, $CloseTag-$i); // Get the list + $i = $CloseTag; // 5d) Move the pointer past the end of the [/close] tag. + } else { + //5b) If it's a normal tag, it may have versions of itself nested inside + $CloseTag = $i-1; + $InTagPos = $i-1; + $NumInOpens = 0; + $NumInCloses = -1; + + $InOpenRegex = '/\[('.$TagName.')'; + if($MaxAttribs>0) { + $InOpenRegex.="(=[^\n'\"\[\]]+)?"; + } + $InOpenRegex.='\]/i'; + + + // Every time we find an internal open tag of the same type, search for the next close tag + // (as the first close tag won't do - it's been opened again) + do { + $CloseTag = stripos($Str, '[/'.$TagName.']', $CloseTag+1); + if($CloseTag === false) { + $CloseTag = $Len; + break; + } else { + $NumInCloses++; // Majority of cases + } + + // Is there another open tag inside this one? + $OpenTag = preg_match($InOpenRegex, $Str, $InTag, PREG_OFFSET_CAPTURE, $InTagPos+1); + if(!$OpenTag || $InTag[0][1]>$CloseTag) { + break; + } else { + $InTagPos = $InTag[0][1]; + $NumInOpens++; + } + + } while($NumInOpens>$NumInCloses); + + + // Find the internal block inside the tag + $Block = substr($Str, $i, $CloseTag-$i); // 5c) Get the contents between [open] and [/close] and call it the block. + + $i = $CloseTag+strlen($TagName)+3; // 5d) Move the pointer past the end of the [/close] tag. + + } + + // 6) Depending on what type of tag we're dealing with, create an array with the attribute and block. + switch($TagName) { + case 'inlineurl': + $Array[$ArrayPos] = array('Type'=>'inlineurl', 'Attr'=>$Block, 'Val'=>''); + break; + case 'url': + $Array[$ArrayPos] = array('Type'=>'img', 'Attr'=>$Attrib, 'Val'=>$Block); + if(empty($Attrib)) { // [url]http://...[/url] - always set URL to attribute + $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Block, 'Val'=>''); + } else { + $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block)); + } + break; + case 'quote': + $Array[$ArrayPos] = array('Type'=>'quote', 'Attr'=>$this->Parse($Attrib), 'Val'=>$this->parse($Block)); + break; + case 'img': + case 'image': + if(empty($Block)) { + $Block = $Attrib; + } + $Array[$ArrayPos] = array('Type'=>'img', 'Val'=>$Block); + break; + case 'aud': + case 'mp3': + case 'audio': + if(empty($Block)) { + $Block = $Attrib; + } + $Array[$ArrayPos] = array('Type'=>'aud', 'Val'=>$Block); + break; + case 'user': + $Array[$ArrayPos] = array('Type'=>'user', 'Val'=>$Block); + break; + case 'artist': + $Array[$ArrayPos] = array('Type'=>'artist', 'Val'=>$Block); + break; + case 'torrent': + $Array[$ArrayPos] = array('Type'=>'torrent', 'Val'=>$Block); + break; + case 'tex': + $Array[$ArrayPos] = array('Type'=>'tex', 'Val'=>$Block); + break; + case 'pre': + case 'code': + case 'plain': + $Block = strtr($Block, array('[inlineurl]'=>'')); + $Block = preg_replace('/\[inlinesize\=3\](.*?)\[\/inlinesize\]/i', '====$1====', $Block); + $Block = preg_replace('/\[inlinesize\=5\](.*?)\[\/inlinesize\]/i', '===$1===', $Block); + $Block = preg_replace('/\[inlinesize\=7\](.*?)\[\/inlinesize\]/i', '==$1==', $Block); + + $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$Block); + break; + case 'hide': + $Array[$ArrayPos] = array('Type'=>'hide', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block)); + break; + case '#': + case '*': + $Array[$ArrayPos] = array('Type'=>'list'); + $Array[$ArrayPos]['Val'] = explode('['.$TagName.']', $Block); + $Array[$ArrayPos]['ListType'] = $TagName === '*' ? 'ul' : 'ol'; + $Array[$ArrayPos]['Tag'] = $TagName; + foreach($Array[$ArrayPos]['Val'] as $Key=>$Val) { + $Array[$ArrayPos]['Val'][$Key] = $this->parse(trim($Val)); + } + break; + case 'n': + $ArrayPos--; + break; // n serves only to disrupt bbcode (backwards compatibility - use [pre]) + default: + if($WikiLink == true) { + $Array[$ArrayPos] = array('Type'=>'wiki','Val'=>$TagName); + } else { + + // Basic tags, like [b] or [size=5] + + $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$this->parse($Block)); + if(!empty($Attrib) && $MaxAttribs>0) { + $Array[$ArrayPos]['Attr'] = strtolower($Attrib); + } + } + } + + $ArrayPos++; // 7) Increment array pointer, start again (past the end of the [/close] tag) + } + return $Array; + } + + function to_html($Array) { + $this->Levels++; + if($this->Levels>10) { return $Block['Val']; } // Hax prevention + $Str = ''; + + foreach($Array as $Block) { + if(is_string($Block)) { + $Str.=$this->smileys($Block); + continue; + } + switch($Block['Type']) { + case 'b': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'u': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'i': + $Str.=''.$this->to_html($Block['Val']).""; + break; + case 's': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'important': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'user': + $Str.=''.$Block['Val'].''; + break; + case 'artist': + $Str.=''.$Block['Val'].''; + break; + case 'torrent': + $Pattern = '/('.NONSSL_SITE_URL.'\/torrents\.php.*[\?&]id=)?(\d+)($|&|\#).*/i'; + $Matches = array(); + if (preg_match($Pattern, $Block['Val'], $Matches)) { + if (isset($Matches[2])) { + $Groups = get_groups(array($Matches[2]), true, true, false); + if (!empty($Groups['matches'][$Matches[2]])) { + $Group = $Groups['matches'][$Matches[2]]; + $Str .= display_artists($Group['ExtendedArtists']).''.$Group['Name'].''; + } else { + $Str .= '[torrent]'.str_replace('[inlineurl]','',$Block['Val']).'[/torrent]'; + } + } + } else { + $Str .= '[torrent]'.str_replace('[inlineurl]','',$Block['Val']).'[/torrent]'; + } + break; + case 'wiki': + $Str.=''.$Block['Val'].''; + break; + case 'tex': + $Str.=''; + break; + case 'plain': + $Str.=$Block['Val']; + break; + case 'pre': + $Str.='
    '.$Block['Val'].'
    '; + break; + case 'code': + $Str.=''.$Block['Val'].''; + break; + case 'list': + $Str .= '<'.$Block['ListType'].'>'; + foreach($Block['Val'] as $Line) { + + $Str.='
  3. '.$this->to_html($Line).'
  4. '; + } + $Str.=''; + break; + case 'align': + $ValidAttribs = array('left', 'center', 'right'); + if(!in_array($Block['Attr'], $ValidAttribs)) { + $Str.='[align='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/align]'; + } else { + $Str.='
    '.$this->to_html($Block['Val']).'
    '; + } + break; + case 'color': + case 'colour': + $ValidAttribs = array('aqua', 'black', 'blue', 'fuchsia', 'green', 'grey', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow'); + if(!in_array($Block['Attr'], $ValidAttribs) && !preg_match('/^#[0-9a-f]{6}$/', $Block['Attr'])) { + $Str.='[color='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/color]'; + } else { + $Str.=''.$this->to_html($Block['Val']).''; + } + break; + case 'inlinesize': + case 'size': + $ValidAttribs = array('1','2','3','4','5','6','7','8','9','10'); + if(!in_array($Block['Attr'], $ValidAttribs)) { + $Str.='[size='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/size]'; + } else { + $Str.=''.$this->to_html($Block['Val']).''; + } + break; + case 'quote': + $this->NoImg++; // No images inside quote tags + if(!empty($Block['Attr'])) { + $Str.= ''.$this->to_html($Block['Attr']).' wrote: '; + } + $Str.='
    '.$this->to_html($Block['Val']).'
    '; + $this->NoImg--; + break; + case 'hide': + $Str.=''.(($Block['Attr']) ? $Block['Attr'] : 'Hidden text').': Show'; + $Str.=''; + break; + case 'img': + if($this->NoImg>0 && $this->valid_url($Block['Val'])) { + $Str.=''.$Block['Val'].' (image)'; + break; + } + if(!$this->valid_url($Block['Val'], '\.(jpe?g|gif|png|bmp|tiff)')) { + $Str.='[img]'.$Block['Val'].'[/img]'; + } else { + $LocalURL = $this->local_url($Block['Val']); + if($LocalURL) { + $Str.=''.$Block['Val'].''; + } elseif(check_perms('site_proxy_images')) { + $Str.=''.$Block['Val'].''; + } else { + $Str.=''.$Block['Val'].''; + } + } + break; + + case 'aud': + if($this->NoImg>0 && $this->valid_url($Block['Val'])) { + $Str.=''.$Block['Val'].' (audio)'; + break; + } + if(!$this->valid_url($Block['Val'], '\.(mp3|ogg|wav)')) { + $Str.='[aud]'.$Block['Val'].'[/aud]'; + } else { + //TODO: Proxy this for staff? + $Str.=''; + } + break; + + case 'url': + // Make sure the URL has a label + if(empty($Block['Val'])) { + $Block['Val'] = $Block['Attr']; + $NoName = true; // If there isn't a Val for this + } else { + $Block['Val'] = $this->to_html($Block['Val']); + $NoName = false; + } + + if(!$this->valid_url($Block['Attr'])) { + $Str.='[url='.$Block['Attr'].']'.$Block['Val'].'[/url]'; + } else { + $LocalURL = $this->local_url($Block['Attr']); + if($LocalURL) { + if($NoName) { $Block['Val'] = substr($LocalURL,1); } + $Str.=''.$Block['Val'].''; + } else { + $Str.=''.$Block['Val'].''; + } + } + break; + + case 'inlineurl': + if(!$this->valid_url($Block['Attr'], '', true)) { + $Array = $this->parse($Block['Attr']); + $Block['Attr'] = $Array; + $Str.=$this->to_html($Block['Attr']); + } + + else { + $LocalURL = $this->local_url($Block['Attr']); + if($LocalURL) { + $Str.=''.substr($LocalURL,1).''; + } else { + $Str.=''.$Block['Attr'].''; + } + } + + break; + + } + } + $this->Levels--; + return $Str; + } + + function raw_text($Array) { + $Str = ''; + foreach($Array as $Block) { + if(is_string($Block)) { + $Str.=$Block; + continue; + } + switch($Block['Type']) { + + case 'b': + case 'u': + case 'i': + case 's': + case 'color': + case 'size': + case 'quote': + case 'align': + + $Str.=$this->raw_text($Block['Val']); + break; + case 'tex': //since this will never strip cleanly, just remove it + break; + case 'artist': + case 'user': + case 'wiki': + case 'pre': + case 'code': + case 'aud': + case 'img': + $Str.=$Block['Val']; + break; + case 'list': + foreach($Block['Val'] as $Line) { + $Str.=$Block['Tag'].$this->raw_text($Line); + } + break; + + case 'url': + // Make sure the URL has a label + if(empty($Block['Val'])) { + $Block['Val'] = $Block['Attr']; + } else { + $Block['Val'] = $this->raw_text($Block['Val']); + } + + $Str.=$Block['Val']; + break; + + case 'inlineurl': + if(!$this->valid_url($Block['Attr'], '', true)) { + $Array = $this->parse($Block['Attr']); + $Block['Attr'] = $Array; + $Str.=$this->raw_text($Block['Attr']); + } + else { + $Str.=$Block['Attr']; + } + + break; + } + } + return $Str; + } + + function smileys($Str) { + global $LoggedUser; + if(!empty($LoggedUser['DisableSmileys'])) { + return $Str; + } + $Str = strtr($Str, $this->Smileys); + return $Str; + } +} +/* + +//Uncomment this part to test the class via command line: +function display_str($Str) {return $Str;} +function check_perms($Perm) {return true;} +$Str = "hello +[pre]http://anonym.to/?http://whatshirts.portmerch.com/ +====hi==== +===hi=== +==hi==[/pre] +====hi==== +hi"; +$Text = NEW TEXT; +echo $Text->full_format($Str); +echo "\n" +*/ +?> diff --git a/classes/class_text2.php b/classes/class_text2.php new file mode 100644 index 00000000..a77a1a15 --- /dev/null +++ b/classes/class_text2.php @@ -0,0 +1,701 @@ +max number of attributes + private $ValidTags = array('b'=>0, 'u'=>0, 'i'=>0, 's'=>0, '*'=>0, 'artist'=>0, 'user'=>0, 'n'=>0, 'inlineurl'=>0, 'inlinesize'=>1, 'align'=>1, 'color'=>1, 'colour'=>1, 'size'=>1, 'url'=>1, 'img'=>1, 'quote'=>1, 'pre'=>1, 'code'=>1, 'tex'=>0, 'hide'=>1, 'plain'=>0 + ); + private $Smileys = array( + ':angry:' => 'angry.gif', + ':-D' => 'biggrin.gif', + ':D' => 'biggrin.gif', + ':|' => 'blank.gif', + ':-|' => 'blank.gif', + ':blush:' => 'blush.gif', + ':cool:' => 'cool.gif', + ':'(' => 'crying.gif', + ':crying:' => 'crying.gif', + '>.>' => 'eyesright.gif', + ':frown:' => 'frown.gif', + '<3' => 'heart.gif', + ':unsure:' => 'hmm.gif', + ':\\' => 'hmm.gif', + ':whatlove:' => 'ilu.gif', + ':lol:' => 'laughing.gif', + ':loveflac:' => 'loveflac.gif', + ':ninja:' => 'ninja.gif', + ':no:' => 'no.gif', + ':nod:' => 'nod.gif', + ':ohno:' => 'ohnoes.gif', + ':ohnoes:' => 'ohnoes.gif', + ':omg:' => 'omg.gif', + ':o' => 'ohshit.gif', + ':O' => 'ohshit.gif', + ':paddle:' => 'paddle.gif', + ':(' => 'sad.gif', + ':-(' => 'sad.gif', + ':shifty:' => 'shifty.gif', + ':sick:' => 'sick.gif', + ':)' => 'smile.gif', + ':-)' => 'smile.gif', + ':sorry:' => 'sorry.gif', + ':thanks:' => 'thanks.gif', + ':P' => 'tongue.gif', + ':-P' => 'tongue.gif', + ':-p' => 'tongue.gif', + ':wave:' => 'wave.gif', + ';-)' => 'wink.gif', + ':wink:' => 'wink.gif', + ':creepy:' => 'creepy.gif', + ':worried:' => 'worried.gif', + ':wtf:' => 'wtf.gif', + ':wub:' => 'wub.gif', + ); + + private $NoImg = 0; // If images should be turned into URLs + private $Levels = 0; // If images should be turned into URLs + + function __construct() { + foreach($this->Smileys as $Key=>$Val) { + $this->Smileys[$Key] = ''; + } + reset($this->Smileys); + } + + function full_format($Str) { + $Str = display_str($Str); + + //Inline links + $URLPrefix = '(\[url\]|\[url\=|\[img\=|\[img\])'; + $Str = preg_replace('/'.$URLPrefix.'\s+http/i', '$1http', $Str); + $Str = preg_replace('/(?'?http', '=[inlineurl]http'=>'=http')); + $callback = create_function('$matches', 'return str_replace("[inlineurl]","",$matches[0]);'); + $Str = preg_replace_callback('/(?<=\[inlineurl\]|'.$URLPrefix.')(\S*\[inlineurl\]\S*)/m', $callback, $Str); + + $Str = preg_replace('/\=\=\=\=([^=].*)\=\=\=\=/i', '[inlinesize=3]$1[/inlinesize]', $Str); + $Str = preg_replace('/\=\=\=([^=].*)\=\=\=/i', '[inlinesize=5]$1[/inlinesize]', $Str); + $Str = preg_replace('/\=\=([^=].*)\=\=/i', '[inlinesize=7]$1[/inlinesize]', $Str); + + $Str = $this->parse($Str); + + $HTML = $this->to_html($Str); + + $HTML = nl2br($HTML); + return $HTML; + } + + function strip_bbcode($Str) { + $Str = display_str($Str); + + //Inline links + $Str = preg_replace('/(?parse($Str); + + $Str = $this->raw_text($Str); + + $Str = nl2br($Str); + return $Str; + } + + + function valid_url($Str, $Extension = '', $Inline = false) { + $Regex = '/^'; + $Regex .= '(https?|ftps?|irc):\/\/'; // protocol + $Regex .= '(\w+(:\w+)?@)?'; // user:pass@ + $Regex .= '('; + $Regex .= '(([0-9]{1,3}\.){3}[0-9]{1,3})|'; // IP or... + $Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})'; // sub.sub.sub.host.com + $Regex .= ')'; + $Regex .= '(:[0-9]{1,5})?'; // port + $Regex .= '\/?'; // slash? + $Regex .= '(\/?[0-9a-z\-_.,&=@~%\/:;()+|!#]+)*'; // /file + if(!empty($Extension)) { + $Regex.=$Extension; + } + + // query string + if ($Inline) { + $Regex .= '(\?([0-9a-z\-_.,%\/\@~&=:;()+*\^$!#|]|\[\d*\])*)?'; + } else { + $Regex .= '(\?[0-9a-z\-_.,%\/\@[\]~&=:;()+*\^$!#|]*)?'; + } + + $Regex .= '(#[a-z0-9\-_.,%\/\@[\]~&=:;()+*\^$!]*)?'; // #anchor + $Regex .= '$/i'; + + return preg_match($Regex, $Str, $Matches); + } + + function local_url($Str) { + $URLInfo = parse_url($Str); + if(!$URLInfo) { return false; } + $Host = $URLInfo['host']; + // If for some reason your site does not require subdomains or contains a directory in the SITE_URL, revert to the line below. + //if($Host == NONSSL_SITE_URL || $Host == SSL_SITE_URL || $Host == 'www.'.NONSSL_SITE_URL) { + if(preg_match('/(\S+\.)*'.NONSSL_SITE_URL.'/', $Host)) { + $URL = $URLInfo['path']; + if(!empty($URLInfo['query'])) { + $URL.='?'.$URLInfo['query']; + } + if(!empty($URLInfo['fragment'])) { + $URL.='#'.$URLInfo['fragment']; + } + return $URL; + } else { + return false; + } + + } + + +/* How parsing works + +Parsing takes $Str, breaks it into blocks, and builds it into $Array. +Blocks start at the beginning of $Str, when the parser encounters a [, and after a tag has been closed. +This is all done in a loop. + +EXPLANATION OF PARSER LOGIC + +1) Find and parse the next tag (regex) + 1a) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name + 1b) If it's not a wiki link: + 1bi) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit] + 1bii) Get the attribute, if it exists [name=attribute] + If it's [not a tag] or has an invalid attribute, just leave it as plaintext and move on +2) If there aren't any tags left, write everything remaining to a block and return (done parsing) +3) If the next tag isn't where the pointer is, write everything up to there to a text block. +4) Move the pointer past the end of the tag +5) Find out where the tag closes (beginning of [/tag]) + 5a) Different for different types of tag. Some tags don't close, others are weird like [*] + 5b) If it's a normal tag, it may have versions of itself nested inside - eg: + [quote=bob]* + [quote=joe]I am a redneck!**[/quote] + Me too! + ***[/quote] + If we're at the position *, the first [/quote] tag is denoted by **. + However, our quote tag doesn't actually close there. We must perform + a loop which checks the number of opening [quote] tags, and make sure + they are all closed before we find our final [/quote] tag (***). + + 5c) Get the contents between [open] and [/close] and call it the block. + In many cases, this will be parsed itself later on, in a new parse() call. + 5d) Move the pointer past the end of the [/close] tag. +6) Depending on what type of tag we're dealing with, create an array with the attribute and block. + In many cases, the block may be parsed here itself. Stick them in the $Array. +7) Increment array pointer, start again (past the end of the [/close] tag) + +*/ + function parse($Str) { + $i = 0; // Pointer to keep track of where we are in $Str + $Len = strlen($Str); + $Array = array(); + $ArrayPos = 0; + + while($i<$Len) { + $Block = ''; + + // 1) Find and parse the next tag (regex) + // [name=|[name]|[[wiki-link]] + $IsTag = preg_match("/((\[[a-zA-Z*]{1,100})([=\]]))|(\[\[[^\n\"'\[\]]+\]\])/", $Str, $Tag, PREG_OFFSET_CAPTURE, $i); + $TagPos = $Tag[0][1]; + // At this point we still don't know whether the tag code is valid + // $IsTag will be updated with new information + + // 1a) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name + if ($IsTag && !empty($Tag[4][0])) { // Wiki-link + $WikiLink = true; + $TagName = substr($Tag[4][0], 2, -2); + $Attrib = ''; + $ExtraTagLen = 0; + } elseif ($IsTag) { // 1b) If it's not a wiki link: + $WikiLink = false; + $TagName = strtolower(substr($Tag[2][0], 1)); + + $MaxAttribs = $this->ValidTags[$TagName]; + + // 1bi) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit] + if(!isset($this->ValidTags[$TagName])) { + $IsTag = 0; + } + + // 1bii) Get the attribute, if it exists [name=attribute] + $HasAttrib = ($Tag[3][0] == '='); + if ($IsTag && $HasAttrib) { + $AttribFrom = $TagPos + strlen($Tag[0][0]); + $Attrib = substr($Str, $AttribFrom, strpos($Str, ']', $AttribFrom) - $AttribFrom); + $ExtraTagLen = strlen($Attrib) + 1; + // check $Attrib is valid, i.e. the tag is in a valid format + // disallowed characters + if ((strpos($Attrib, "\n") !== false) + || (strpos($Attrib, "'") !== false) + || (strpos($Attrib, "\"") !== false)) { + $IsTag = 0; + } elseif (strpos($Attrib, "[") !== false) { + // attributes aren't allowed to contain any tag (or something which looks like it might be one) inside them + foreach ($this->ValidTags as $PossibleTag=>$_) { + if (strpos($Attrib, "[".$PossibleTag) !== false) { + $IsTag = 0; + } + } + } + } else { + $Attrib = ''; + $ExtraTagLen = 0; + } + + if (!$IsTag) { + // we jump past the beginning of the "tag", but not the attribute value, as this may contain real tags + $Array[$ArrayPos] = substr($Str, $i, ($TagPos-$i)+strlen($Tag[0][0])); + $i=$TagPos+strlen($Tag[0][0]); + ++$ArrayPos; + continue; + } + + } + + // 2) If there aren't any tags left, write everything remaining to a block + if(!$IsTag) { + // No more tags + $Array[$ArrayPos] = substr($Str, $i); + break; + } + + // 3) If the next tag isn't where the pointer is, write everything up to there to a text block. + if($TagPos>$i) { + $Array[$ArrayPos] = substr($Str, $i, $TagPos-$i); + ++$ArrayPos; + $i=$TagPos; + } + + // 4) Move the pointer past the end of the tag + $i=$TagPos+strlen($Tag[0][0])+$ExtraTagLen; + + // 5) Find out where the tag closes (beginning of [/tag]) + + // Unfortunately, BBCode doesn't have nice standards like xhtml + // [*], [img=...], and http:// follow different formats + // Thus, we have to handle these before we handle the majority of tags + + + //5a) Different for different types of tag. Some tags don't close, others are weird like [*] + if($TagName == 'img' && $HasAttrib) { //[img=...] + $Block = ''; // Nothing inside this tag + // Don't need to touch $i + } elseif($TagName == 'inlineurl') { // We did a big replace early on to turn http:// into [inlineurl]http:// + + // Let's say the block can stop at a newline or a space + $CloseTag = strcspn($Str, " \n\r", $i); + if($CloseTag === false) { // block finishes with URL + $CloseTag = $Len; + } + if(preg_match('/[!;,.?:]+$/',substr($Str, $i, $CloseTag), $Match)) { + $CloseTag -= strlen($Match[0]); + } + $URL = substr($Str, $i, $CloseTag); + if(substr($URL, -1) == ')' && substr_count($URL, '(') < substr_count($URL, ')')) { + $CloseTag--; + $URL = substr($URL, 0, -1); + } + $Block = $URL; // Get the URL + + // strcspn returns the number of characters after the offset $i, not after the beginning of the string + // Therefore, we use += instead of the = everywhere else + $i += $CloseTag; // 5d) Move the pointer past the end of the [/close] tag. + } elseif($WikiLink == true || $TagName == 'n') { + // Don't need to do anything - empty tag with no closing + } elseif($TagName == '*') { + // We're in a list. Find where it ends + $NewLine = $i; + do { // Look for \n[*] + $NewLine = strpos($Str, "\n", $NewLine+1); + } while($NewLine!== false && substr($Str, $NewLine+1, 3) == '[*]'); + + $CloseTag = $NewLine; + if($CloseTag === false) { // block finishes with list + $CloseTag = $Len; + } + $Block = substr($Str, $i, $CloseTag-$i); // Get the list + $i = $CloseTag; // 5d) Move the pointer past the end of the [/close] tag. + } else { + //5b) If it's a normal tag, it may have versions of itself nested inside + $CloseTag = $i-1; + $InTagPos = $i-1; + $NumInOpens = 0; + $NumInCloses = -1; + + $InOpenRegex = '/\[('.$TagName.')'; + if($MaxAttribs>0) { + $InOpenRegex.="(=[^\n'\"\[\]]+)?"; + } + $InOpenRegex.='\]/i'; + + + // Every time we find an internal open tag of the same type, search for the next close tag + // (as the first close tag won't do - it's been opened again) + do { + $CloseTag = stripos($Str, '[/'.$TagName.']', $CloseTag+1); + if($CloseTag === false) { + $CloseTag = $Len; + break; + } else { + $NumInCloses++; // Majority of cases + } + + // Is there another open tag inside this one? + $OpenTag = preg_match($InOpenRegex, $Str, $InTag, PREG_OFFSET_CAPTURE, $InTagPos+1); + if(!$OpenTag || $InTag[0][1]>$CloseTag) { + break; + } else { + $InTagPos = $InTag[0][1]; + $NumInOpens++; + } + + } while($NumInOpens>$NumInCloses); + + + // Find the internal block inside the tag + $Block = substr($Str, $i, $CloseTag-$i); // 5c) Get the contents between [open] and [/close] and call it the block. + + $i = $CloseTag+strlen($TagName)+3; // 5d) Move the pointer past the end of the [/close] tag. + + } + + // 6) Depending on what type of tag we're dealing with, create an array with the attribute and block. + switch($TagName) { + case 'inlineurl': + $Array[$ArrayPos] = array('Type'=>'inlineurl', 'Attr'=>$Block, 'Val'=>''); + break; + case 'url': + $Array[$ArrayPos] = array('Type'=>'img', 'Attr'=>$Attrib, 'Val'=>$Block); + if(empty($Attrib)) { // [url]http://...[/url] - always set URL to attribute + $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Block, 'Val'=>''); + } else { + $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block)); + } + break; + case 'quote': + $Array[$ArrayPos] = array('Type'=>'quote', 'Attr'=>$this->Parse($Attrib), 'Val'=>$this->parse($Block)); + break; + case 'img': + case 'image': + if(empty($Block)) { + $Block = $Attrib; + } + $Array[$ArrayPos] = array('Type'=>'img', 'Val'=>$Block); + break; + case 'aud': + case 'mp3': + case 'audio': + if(empty($Block)) { + $Block = $Attrib; + } + $Array[$ArrayPos] = array('Type'=>'aud', 'Val'=>$Block); + break; + case 'user': + $Array[$ArrayPos] = array('Type'=>'user', 'Val'=>$Block); + break; + case 'artist': + $Array[$ArrayPos] = array('Type'=>'artist', 'Val'=>$Block); + break; + case 'tex': + $Array[$ArrayPos] = array('Type'=>'tex', 'Val'=>$Block); + break; + case 'pre': + case 'code': + case 'plain': + $Block = strtr($Block, array('[inlineurl]'=>'')); + $Block = preg_replace('/\[inlinesize\=3\](.*?)\[\/inlinesize\]/i', '====$1====', $Block); + $Block = preg_replace('/\[inlinesize\=5\](.*?)\[\/inlinesize\]/i', '===$1===', $Block); + $Block = preg_replace('/\[inlinesize\=7\](.*?)\[\/inlinesize\]/i', '==$1==', $Block); + + $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$Block); + break; + case 'hide': + $Array[$ArrayPos] = array('Type'=>'hide', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block)); + break; + case '*': + $Array[$ArrayPos] = array('Type'=>'list'); + $Array[$ArrayPos]['Val'] = explode('[*]', $Block); + foreach($Array[$ArrayPos]['Val'] as $Key=>$Val) { + $Array[$ArrayPos]['Val'][$Key] = $this->parse(trim($Val)); + } + break; + case 'n': + $ArrayPos--; + break; // n serves only to disrupt bbcode (backwards compatibility - use [pre]) + default: + if($WikiLink == true) { + $Array[$ArrayPos] = array('Type'=>'wiki','Val'=>$TagName); + } else { + + // Basic tags, like [b] or [size=5] + + $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$this->parse($Block)); + if(!empty($Attrib) && $MaxAttribs>0) { + $Array[$ArrayPos]['Attr'] = strtolower($Attrib); + } + } + } + + $ArrayPos++; // 7) Increment array pointer, start again (past the end of the [/close] tag) + } + return $Array; + } + + function to_html($Array) { + $this->Levels++; + if($this->Levels>10) { return $Block['Val']; } // Hax prevention + $Str = ''; + + foreach($Array as $Block) { + if(is_string($Block)) { + $Str.=$this->smileys($Block); + continue; + } + switch($Block['Type']) { + case 'b': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'u': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'i': + $Str.=''.$this->to_html($Block['Val']).""; + break; + case 's': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'user': + $Str.=''.$Block['Val'].''; + break; + case 'artist': + $Str.=''.$Block['Val'].''; + break; + case 'wiki': + $Str.=''.$Block['Val'].''; + break; + case 'tex': + $Str.=''; + break; + case 'plain': + $Str.=$Block['Val']; + break; + case 'pre': + $Str.='
    '.$Block['Val'].'
    '; + break; + case 'code': + $Str.=''.$Block['Val'].''; + break; + case 'list': + $Str .= '
      '; + foreach($Block['Val'] as $Line) { + + $Str.='
    • '.$this->to_html($Line).'
    • '; + } + $Str.='
    '; + break; + case 'align': + $ValidAttribs = array('left', 'center', 'right'); + if(!in_array($Block['Attr'], $ValidAttribs)) { + $Str.='[align='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/align]'; + } else { + $Str.='
    '.$this->to_html($Block['Val']).'
    '; + } + break; + case 'color': + case 'colour': + $ValidAttribs = array('aqua', 'black', 'blue', 'fuchsia', 'green', 'grey', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow'); + if(!in_array($Block['Attr'], $ValidAttribs) && !preg_match('/^#[0-9a-f]{6}$/', $Block['Attr'])) { + $Str.='[color='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/color]'; + } else { + $Str.=''.$this->to_html($Block['Val']).''; + } + break; + case 'inlinesize': + case 'size': + $ValidAttribs = array('1','2','3','4','5','6','7','8','9','10'); + if(!in_array($Block['Attr'], $ValidAttribs)) { + $Str.='[size='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/size]'; + } else { + $Str.=''.$this->to_html($Block['Val']).''; + } + break; + case 'quote': + $this->NoImg++; // No images inside quote tags + if(!empty($Block['Attr'])) { + $Str.= ''.$this->to_html($Block['Attr']).' wrote: '; + } + $Str.='
    '.$this->to_html($Block['Val']).'
    '; + $this->NoImg--; + break; + case 'hide': + $Str.=''.(($Block['Attr']) ? $Block['Attr'] : 'Hidden text').': Show'; + $Str.=''; + break; + case 'img': + if($this->NoImg>0 && $this->valid_url($Block['Val'])) { + $Str.=''.$Block['Val'].' (image)'; + break; + } + if(!$this->valid_url($Block['Val'], '\.(jpe?g|gif|png|bmp|tiff)')) { + $Str.='[img]'.$Block['Val'].'[/img]'; + } else { + if(check_perms('site_proxy_images')) { + $Str.=''.$Block['Val'].''; + } else { + $Str.=''.$Block['Val'].''; + } + } + break; + + case 'aud': + if($this->NoImg>0 && $this->valid_url($Block['Val'])) { + $Str.=''.$Block['Val'].' (audio)'; + break; + } + if(!$this->valid_url($Block['Val'], '\.(mp3|ogg|wav)')) { + $Str.='[aud]'.$Block['Val'].'[/aud]'; + } else { + //TODO: Proxy this for staff? + $Str.=''; + } + break; + + case 'url': + // Make sure the URL has a label + if(empty($Block['Val'])) { + $Block['Val'] = $Block['Attr']; + $NoName = true; // If there isn't a Val for this + } else { + $Block['Val'] = $this->to_html($Block['Val']); + $NoName = false; + } + + if(!$this->valid_url($Block['Attr'])) { + $Str.='[url='.$Block['Attr'].']'.$Block['Val'].'[/url]'; + } else { + $LocalURL = $this->local_url($Block['Attr']); + if($LocalURL) { + if($NoName) { $Block['Val'] = substr($LocalURL,1); } + $Str.=''.$Block['Val'].''; + } else { + $Str.=''.$Block['Val'].''; + } + } + break; + + case 'inlineurl': + if(!$this->valid_url($Block['Attr'], '', true)) { + $Array = $this->parse($Block['Attr']); + $Block['Attr'] = $Array; + $Str.=$this->to_html($Block['Attr']); + } + + else { + $LocalURL = $this->local_url($Block['Attr']); + if($LocalURL) { + $Str.=''.substr($LocalURL,1).''; + } else { + $Str.=''.$Block['Attr'].''; + } + } + + break; + + } + } + $this->Levels--; + return $Str; + } + + function raw_text($Array) { + $Str = ''; + foreach($Array as $Block) { + if(is_string($Block)) { + $Str.=$Block; + continue; + } + switch($Block['Type']) { + + case 'b': + case 'u': + case 'i': + case 's': + case 'color': + case 'size': + case 'quote': + case 'align': + + $Str.=$this->raw_text($Block['Val']); + break; + case 'tex': //since this will never strip cleanly, just remove it + break; + case 'artist': + case 'user': + case 'wiki': + case 'pre': + case 'code': + case 'aud': + case 'img': + $Str.=$Block['Val']; + break; + case 'list': + foreach($Block['Val'] as $Line) { + $Str.='*'.$this->raw_text($Line); + } + break; + + case 'url': + // Make sure the URL has a label + if(empty($Block['Val'])) { + $Block['Val'] = $Block['Attr']; + } else { + $Block['Val'] = $this->raw_text($Block['Val']); + } + + $Str.=$Block['Val']; + break; + + case 'inlineurl': + if(!$this->valid_url($Block['Attr'], '', true)) { + $Array = $this->parse($Block['Attr']); + $Block['Attr'] = $Array; + $Str.=$this->raw_text($Block['Attr']); + } + else { + $Str.=$Block['Attr']; + } + + break; + } + } + return $Str; + } + + function smileys($Str) { + global $LoggedUser; + if(!empty($LoggedUser['DisableSmileys'])) { + return $Str; + } + $Str = strtr($Str, $this->Smileys); + return $Str; + } +} +/* + +//Uncomment this part to test the class via command line: +function display_str($Str) {return $Str;} +function check_perms($Perm) {return true;} +$Str = "hello +[pre]http://anonym.to/?http://whatshirts.portmerch.com/ +====hi==== +===hi=== +==hi==[/pre] +====hi==== +hi"; +$Text = NEW TEXT; +echo $Text->full_format($Str); +echo "\n" +*/ +?> diff --git a/classes/class_text3.php b/classes/class_text3.php new file mode 100644 index 00000000..2f6e0692 --- /dev/null +++ b/classes/class_text3.php @@ -0,0 +1,661 @@ +max number of attributes + private $ValidTags = array('b'=>0, 'u'=>0, 'i'=>0, 's'=>0, '*'=>0, 'artist'=>0, 'user'=>0, 'n'=>0, 'inlineurl'=>0, 'inlinesize'=>1, 'align'=>1, 'color'=>1, 'colour'=>1, 'size'=>1, 'url'=>1, 'img'=>1, 'quote'=>1, 'pre'=>1, 'tex'=>0, 'hide'=>1, 'plain'=>0 + ); + private $Smileys = array( + ':angry:' => 'angry.gif', + ':-D' => 'biggrin.gif', + ':D' => 'biggrin.gif', + ':|' => 'blank.gif', + ':-|' => 'blank.gif', + ':blush:' => 'blush.gif', + ':cool:' => 'cool.gif', + ':\'(' => 'crying.gif', + '>.>' => 'eyesright.gif', + ':frown:' => 'frown.gif', + '<3' => 'heart.gif', + ':unsure:' => 'hmm.gif', + ':whatlove:' => 'ilu.gif', + ':lol:' => 'laughing.gif', + ':loveflac:' => 'loveflac.gif', + ':ninja:' => 'ninja.gif', + ':no:' => 'no.gif', + ':nod:' => 'nod.gif', + ':ohno:' => 'ohnoes.gif', + ':ohnoes:' => 'ohnoes.gif', + ':omg:' => 'omg.gif', + ':o' => 'ohshit.gif', + ':O' => 'ohshit.gif', + ':paddle:' => 'paddle.gif', + ':(' => 'sad.gif', + ':-(' => 'sad.gif', + ':shifty:' => 'shifty.gif', + ':sick:' => 'sick.gif', + ':)' => 'smile.gif', + ':-)' => 'smile.gif', + ':sorry:' => 'sorry.gif', + ':thanks:' => 'thanks.gif', + ':P' => 'tongue.gif', + ':-P' => 'tongue.gif', + ':-p' => 'tongue.gif', + ':wave:' => 'wave.gif', + ':wink:' => 'wink.gif', + ':creepy:' => 'creepy.gif', + ':worried:' => 'worried.gif', + ':wtf:' => 'wtf.gif', + ':wub:' => 'wub.gif' + ); + + private $NoImg = 0; // If images should be turned into URLs + private $Levels = 0; // If images should be turned into URLs + + function __construct() { + foreach($this->Smileys as $Key=>$Val) { + $this->Smileys[$Key] = ''; + } + reset($this->Smileys); + } + + function full_format($Str) { + $Str = display_str($Str); + + //Inline links + $Str = preg_replace('/(?'?http', '=[inlineurl]http'=>'=http')); + $Str = preg_replace('/\=\=\=\=([^=].*)\=\=\=\=/i', '[inlinesize=3]$1[/inlinesize]', $Str); + $Str = preg_replace('/\=\=\=([^=].*)\=\=\=/i', '[inlinesize=5]$1[/inlinesize]', $Str); + $Str = preg_replace('/\=\=([^=].*)\=\=/i', '[inlinesize=7]$1[/inlinesize]', $Str); + + $Str = $this->parse($Str); + + $HTML = $this->to_html($Str); + + $HTML = nl2br($HTML); + return $HTML; + } + + function strip_bbcode($Str) { + $Str = display_str($Str); + + //Inline links + $Str = preg_replace('/(?parse($Str); + + $Str = $this->raw_text($Str); + + $Str = nl2br($Str); + return $Str; + } + + + function valid_url($Str, $Extension = '', $Inline = false) { + $Regex = '/^'; + $Regex .= '(https?|ftps?|irc):\/\/'; // protocol + $Regex .= '(\w+(:\w+)?@)?'; // user:pass@ + $Regex .= '('; + $Regex .= '(([0-9]{1,3}\.){3}[0-9]{1,3})|'; // IP or... + $Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})'; // sub.sub.sub.host.com + $Regex .= ')'; + $Regex .= '(:[0-9]{1,5})?'; // port + $Regex .= '\/?'; // slash? + $Regex .= '(\/?[0-9a-z\-_.,&=@~%\/:;()+!#]+)*'; // /file + if(!empty($Extension)) { + $Regex.=$Extension; + } + + // query string + if ($Inline) { + $Regex .= '(\?([0-9a-z\-_.,%\/\@~&=:;()+*\^$!#]|\[\d*\])*)?'; + } else { + $Regex .= '(\?[0-9a-z\-_.,%\/\@[\]~&=:;()+*\^$!#]*)?'; + } + + $Regex .= '(#[a-z0-9\-_.,%\/\@[\]~&=:;()+*\^$!]*)?'; // #anchor + $Regex .= '$/i'; + + return preg_match($Regex, $Str, $Matches); + } + + function local_url($Str) { + $URLInfo = parse_url($Str); + if(!$URLInfo) { return false; } + $Host = $URLInfo['host']; + // If for some reason your site does not require subdomains or contains a directory in the SITE_URL, revert to the line below. + //if($Host == NONSSL_SITE_URL || $Host == SSL_SITE_URL || $Host == 'www.'.NONSSL_SITE_URL) { + if(preg_match('/(\S+\.)*'.NONSSL_SITE_URL.'/', $Host)) { + $URL = $URLInfo['path']; + if(!empty($URLInfo['query'])) { + $URL.='?'.$URLInfo['query']; + } + if(!empty($URLInfo['fragment'])) { + $URL.='#'.$URLInfo['fragment']; + } + return $URL; + } else { + return false; + } + + } + + +/* How parsing works + +Parsing takes $Str, breaks it into blocks, and builds it into $Array. +Blocks start at the beginning of $Str, when the parser encounters a [, and after a tag has been closed. +This is all done in a loop. + +EXPLANATION OF PARSER LOGIC + +1) Find the next tag (regex) + 1a) If there aren't any tags left, write everything remaining to a block and return (done parsing) + 1b) If the next tag isn't where the pointer is, write everything up to there to a text block. +2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name +3) If it's not a wiki link: + 3a) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit] + If it's [not a tag], just leave it as plaintext and move on + 3b) Get the attribute, if it exists [name=attribute] +4) Move the pointer past the end of the tag +5) Find out where the tag closes (beginning of [/tag]) + 5a) Different for different types of tag. Some tags don't close, others are weird like [*] + 5b) If it's a normal tag, it may have versions of itself nested inside - eg: + [quote=bob]* + [quote=joe]I am a redneck!**[/quote] + Me too! + ***[/quote] + If we're at the position *, the first [/quote] tag is denoted by **. + However, our quote tag doesn't actually close there. We must perform + a loop which checks the number of opening [quote] tags, and make sure + they are all closed before we find our final [/quote] tag (***). + + 5c) Get the contents between [open] and [/close] and call it the block. + In many cases, this will be parsed itself later on, in a new parse() call. + 5d) Move the pointer past the end of the [/close] tag. +6) Depending on what type of tag we're dealing with, create an array with the attribute and block. + In many cases, the block may be parsed here itself. Stick them in the $Array. +7) Increment array pointer, start again (past the end of the [/close] tag) + +*/ + function parse($Str) { + $i = 0; // Pointer to keep track of where we are in $Str + $Len = strlen($Str); + $Array = array(); + $ArrayPos = 0; + + while($i<$Len) { + $Block = ''; + + // 1) Find the next tag (regex) + // [name(=attribute)?]|[[wiki-link]] + $IsTag = preg_match("/((\[[a-zA-Z*]+)(=(?:[^\n'\"\[\]]|\[\d*\])+)?\])|(\[\[[^\n\"'\[\]]+\]\])/", $Str, $Tag, PREG_OFFSET_CAPTURE, $i); + + // 1a) If there aren't any tags left, write everything remaining to a block + if(!$IsTag) { + // No more tags + $Array[$ArrayPos] = substr($Str, $i); + break; + } + + // 1b) If the next tag isn't where the pointer is, write everything up to there to a text block. + $TagPos = $Tag[0][1]; + if($TagPos>$i) { + $Array[$ArrayPos] = substr($Str, $i, $TagPos-$i); + ++$ArrayPos; + $i=$TagPos; + } + + // 2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name + if(!empty($Tag[4][0])) { // Wiki-link + $WikiLink = true; + $TagName = substr($Tag[4][0], 2, -2); + $Attrib = ''; + } else { // 3) If it's not a wiki link: + $WikiLink = false; + $TagName = strtolower(substr($Tag[2][0], 1)); + + //3a) check it against the $this->ValidTags array to see if it's actually a tag and not [bullshit] + if(!isset($this->ValidTags[$TagName])) { + $Array[$ArrayPos] = substr($Str, $i, ($TagPos-$i)+strlen($Tag[0][0])); + $i=$TagPos+strlen($Tag[0][0]); + ++$ArrayPos; + continue; + } + + $MaxAttribs = $this->ValidTags[$TagName]; + + // 3b) Get the attribute, if it exists [name=attribute] + if(!empty($Tag[3][0])) { + $Attrib = substr($Tag[3][0], 1); + } else { + $Attrib=''; + } + } + + // 4) Move the pointer past the end of the tag + $i=$TagPos+strlen($Tag[0][0]); + + // 5) Find out where the tag closes (beginning of [/tag]) + + // Unfortunately, BBCode doesn't have nice standards like xhtml + // [*], [img=...], and http:// follow different formats + // Thus, we have to handle these before we handle the majority of tags + + + //5a) Different for different types of tag. Some tags don't close, others are weird like [*] + if($TagName == 'img' && !empty($Tag[3][0])) { //[img=...] + $Block = ''; // Nothing inside this tag + // Don't need to touch $i + } elseif($TagName == 'inlineurl') { // We did a big replace early on to turn http:// into [inlineurl]http:// + + // Let's say the block can stop at a newline or a space + $CloseTag = strcspn($Str, " \n\r", $i); + if($CloseTag === false) { // block finishes with URL + $CloseTag = $Len; + } + if(preg_match('/[!;,.?:]+$/',substr($Str, $i, $CloseTag), $Match)) { + $CloseTag -= strlen($Match[0]); + } + $URL = substr($Str, $i, $CloseTag); + if(substr($URL, -1) == ')' && substr_count($URL, '(') < substr_count($URL, ')')) { + $CloseTag--; + $URL = substr($URL, 0, -1); + } + $Block = $URL; // Get the URL + + // strcspn returns the number of characters after the offset $i, not after the beginning of the string + // Therefore, we use += instead of the = everywhere else + $i += $CloseTag; // 5d) Move the pointer past the end of the [/close] tag. + } elseif($WikiLink == true || $TagName == 'n') { + // Don't need to do anything - empty tag with no closing + } elseif($TagName == '*') { + // We're in a list. Find where it ends + $NewLine = $i; + do { // Look for \n[*] + $NewLine = strpos($Str, "\n", $NewLine+1); + } while($NewLine!== false && substr($Str, $NewLine+1, 3) == '[*]'); + + $CloseTag = $NewLine; + if($CloseTag === false) { // block finishes with list + $CloseTag = $Len; + } + $Block = substr($Str, $i, $CloseTag-$i); // Get the list + $i = $CloseTag; // 5d) Move the pointer past the end of the [/close] tag. + } else { + //5b) If it's a normal tag, it may have versions of itself nested inside + $CloseTag = $i-1; + $InTagPos = $i-1; + $NumInOpens = 0; + $NumInCloses = -1; + + $InOpenRegex = '/\[('.$TagName.')'; + if($MaxAttribs>0) { + $InOpenRegex.="(=[^\n'\"\[\]]+)?"; + } + $InOpenRegex.='\]/i'; + + + // Every time we find an internal open tag of the same type, search for the next close tag + // (as the first close tag won't do - it's been opened again) + do { + $CloseTag = stripos($Str, '[/'.$TagName.']', $CloseTag+1); + if($CloseTag === false) { + $CloseTag = $Len; + break; + } else { + $NumInCloses++; // Majority of cases + } + + // Is there another open tag inside this one? + $OpenTag = preg_match($InOpenRegex, $Str, $InTag, PREG_OFFSET_CAPTURE, $InTagPos+1); + if(!$OpenTag || $InTag[0][1]>$CloseTag) { + break; + } else { + $InTagPos = $InTag[0][1]; + $NumInOpens++; + } + + } while($NumInOpens>$NumInCloses); + + + // Find the internal block inside the tag + $Block = substr($Str, $i, $CloseTag-$i); // 5c) Get the contents between [open] and [/close] and call it the block. + + $i = $CloseTag+strlen($TagName)+3; // 5d) Move the pointer past the end of the [/close] tag. + + } + + // 6) Depending on what type of tag we're dealing with, create an array with the attribute and block. + switch($TagName) { + case 'inlineurl': + $Array[$ArrayPos] = array('Type'=>'inlineurl', 'Attr'=>$Block, 'Val'=>''); + break; + case 'url': + $Array[$ArrayPos] = array('Type'=>'img', 'Attr'=>$Attrib, 'Val'=>$Block); + if(empty($Attrib)) { // [url]http://...[/url] - always set URL to attribute + $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Block, 'Val'=>''); + } else { + $Array[$ArrayPos] = array('Type'=>'url', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block)); + } + break; + case 'quote': + $Array[$ArrayPos] = array('Type'=>'quote', 'Attr'=>$this->Parse($Attrib), 'Val'=>$this->parse($Block)); + break; + case 'img': + case 'image': + if(empty($Block)) { + $Block = $Attrib; + } + $Array[$ArrayPos] = array('Type'=>'img', 'Val'=>$Block); + break; + case 'aud': + case 'mp3': + case 'audio': + if(empty($Block)) { + $Block = $Attrib; + } + $Array[$ArrayPos] = array('Type'=>'aud', 'Val'=>$Block); + break; + case 'user': + $Array[$ArrayPos] = array('Type'=>'user', 'Val'=>$Block); + break; + case 'artist': + $Array[$ArrayPos] = array('Type'=>'artist', 'Val'=>$Block); + break; + case 'tex': + $Array[$ArrayPos] = array('Type'=>'tex', 'Val'=>$Block); + break; + case 'pre': + case 'plain': + $Block = strtr($Block, array('[inlineurl]'=>'')); + $Block = preg_replace('/\[inlinesize\=3\](.*?)\[\/inlinesize\]/i', '====$1====', $Block); + $Block = preg_replace('/\[inlinesize\=5\](.*?)\[\/inlinesize\]/i', '===$1===', $Block); + $Block = preg_replace('/\[inlinesize\=7\](.*?)\[\/inlinesize\]/i', '==$1==', $Block); + + $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$Block); + break; + case 'hide': + $Array[$ArrayPos] = array('Type'=>'hide', 'Attr'=>$Attrib, 'Val'=>$this->parse($Block)); + break; + case '*': + $Array[$ArrayPos] = array('Type'=>'list'); + $Array[$ArrayPos]['Val'] = explode('[*]', $Block); + foreach($Array[$ArrayPos]['Val'] as $Key=>$Val) { + $Array[$ArrayPos]['Val'][$Key] = $this->parse(trim($Val)); + } + break; + case 'n': + $ArrayPos--; + break; // n serves only to disrupt bbcode (backwards compatibility - use [pre]) + default: + if($WikiLink == true) { + $Array[$ArrayPos] = array('Type'=>'wiki','Val'=>$TagName); + } else { + + // Basic tags, like [b] or [size=5] + + $Array[$ArrayPos] = array('Type'=>$TagName, 'Val'=>$this->parse($Block)); + if(!empty($Attrib) && $MaxAttribs>0) { + $Array[$ArrayPos]['Attr'] = strtolower($Attrib); + } + } + } + + $ArrayPos++; // 7) Increment array pointer, start again (past the end of the [/close] tag) + } + return $Array; + } + + function to_html($Array) { + $this->Levels++; + if($this->Levels>10) { return $Block['Val']; } // Hax prevention + $Str = ''; + + foreach($Array as $Block) { + if(is_string($Block)) { + $Str.=$this->smileys($Block); + continue; + } + switch($Block['Type']) { + case 'b': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'u': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'i': + $Str.=''.$this->to_html($Block['Val']).""; + break; + case 's': + $Str.=''.$this->to_html($Block['Val']).''; + break; + case 'user': + $Str.=''.$Block['Val'].''; + break; + case 'artist': + $Str.=''.$Block['Val'].''; + break; + case 'wiki': + $Str.=''.$Block['Val'].''; + break; + case 'tex': + $Str.=''; + break; + case 'plain': + $Str.=$Block['Val']; + break; + case 'pre': + $Str.='
    '.$Block['Val'].'
    '; + break; + case 'list': + $Str .= '
      '; + foreach($Block['Val'] as $Line) { + + $Str.='
    • '.$this->to_html($Line).'
    • '; + } + $Str.='
    '; + break; + case 'align': + $ValidAttribs = array('left', 'center', 'right'); + if(!in_array($Block['Attr'], $ValidAttribs)) { + $Str.='[align='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/align]'; + } else { + $Str.='
    '.$this->to_html($Block['Val']).'
    '; + } + break; + case 'color': + case 'colour': + $ValidAttribs = array('aqua', 'black', 'blue', 'fuchsia', 'green', 'grey', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow'); + if(!in_array($Block['Attr'], $ValidAttribs) && !preg_match('/^#[0-9a-f]{6}$/', $Block['Attr'])) { + $Str.='[color='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/color]'; + } else { + $Str.=''.$this->to_html($Block['Val']).''; + } + break; + case 'inlinesize': + case 'size': + $ValidAttribs = array('1','2','3','4','5','6','7','8','9','10'); + if(!in_array($Block['Attr'], $ValidAttribs)) { + $Str.='[size='.$Block['Attr'].']'.$this->to_html($Block['Val']).'[/size]'; + } else { + $Str.=''.$this->to_html($Block['Val']).''; + } + break; + case 'quote': + $this->NoImg++; // No images inside quote tags + if(!empty($Block['Attr'])) { + $Str.= ''.$this->to_html($Block['Attr']).' wrote: '; + } + $Str.='
    '.$this->to_html($Block['Val']).'
    '; + $this->NoImg--; + break; + case 'hide': + $Str.=''.(($Block['Attr']) ? $Block['Attr'] : 'Hidden text').': Show'; + $Str.=''; + break; + case 'img': + if($this->NoImg>0 && $this->valid_url($Block['Val'])) { + $Str.=''.$Block['Val'].' (image)'; + break; + } + if(!$this->valid_url($Block['Val'], '\.(jpe?g|gif|png|bmp|tiff)')) { + $Str.='[img]'.$Block['Val'].'[/img]'; + } else { + if(check_perms('site_proxy_images')) { + $Str.=''.$Block['Val'].''; + } else { + $Str.=''.$Block['Val'].''; + } + } + break; + + case 'aud': + if($this->NoImg>0 && $this->valid_url($Block['Val'])) { + $Str.=''.$Block['Val'].' (audio)'; + break; + } + if(!$this->valid_url($Block['Val'], '\.(mp3|ogg|wav)')) { + $Str.='[aud]'.$Block['Val'].'[/aud]'; + } else { + //TODO: Proxy this for staff? + $Str.=''; + } + break; + + case 'url': + // Make sure the URL has a label + if(empty($Block['Val'])) { + $Block['Val'] = $Block['Attr']; + $NoName = true; // If there isn't a Val for this + } else { + $Block['Val'] = $this->to_html($Block['Val']); + $NoName = false; + } + + if(!$this->valid_url($Block['Attr'])) { + $Str.='[url='.$Block['Attr'].']'.$Block['Val'].'[/url]'; + } else { + $LocalURL = $this->local_url($Block['Attr']); + if($LocalURL) { + if($NoName) { $Block['Val'] = substr($LocalURL,1); } + $Str.=''.$Block['Val'].''; + } else { + $Str.=''.$Block['Val'].''; + } + } + break; + + case 'inlineurl': + if(!$this->valid_url($Block['Attr'], '', true)) { + $Array = $this->parse($Block['Attr']); + $Block['Attr'] = $Array; + $Str.=$this->to_html($Block['Attr']); + } + + else { + $LocalURL = $this->local_url($Block['Attr']); + if($LocalURL) { + $Str.=''.substr($LocalURL,1).''; + } else { + $Str.=''.$Block['Attr'].''; + } + } + + break; + + } + } + $this->Levels--; + return $Str; + } + + function raw_text($Array) { + $Str = ''; + foreach($Array as $Block) { + if(is_string($Block)) { + $Str.=$Block; + continue; + } + switch($Block['Type']) { + + case 'b': + case 'u': + case 'i': + case 's': + case 'color': + case 'size': + case 'quote': + case 'align': + + $Str.=$this->raw_text($Block['Val']); + break; + case 'tex': //since this will never strip cleanly, just remove it + break; + case 'artist': + case 'user': + case 'wiki': + case 'pre': + case 'aud': + case 'img': + $Str.=$Block['Val']; + break; + case 'list': + foreach($Block['Val'] as $Line) { + $Str.='*'.$this->raw_text($Line); + } + break; + + case 'url': + // Make sure the URL has a label + if(empty($Block['Val'])) { + $Block['Val'] = $Block['Attr']; + } else { + $Block['Val'] = $this->raw_text($Block['Val']); + } + + $Str.=$Block['Val']; + break; + + case 'inlineurl': + if(!$this->valid_url($Block['Attr'], '', true)) { + $Array = $this->parse($Block['Attr']); + $Block['Attr'] = $Array; + $Str.=$this->raw_text($Block['Attr']); + } + else { + $Str.=$Block['Attr']; + } + + break; + } + } + return $Str; + } + + function smileys($Str) { + global $LoggedUser; + if(!empty($LoggedUser['DisableSmileys'])) { + return $Str; + } + $Str = strtr($Str, $this->Smileys); + return $Str; + } +} +/* + +//Uncomment this part to test the class via command line: +function display_str($Str) {return $Str;} +function check_perms($Perm) {return true;} +$Str = "hello +[pre]http://anonym.to/?http://whatshirts.portmerch.com/ +====hi==== +===hi=== +==hi==[/pre] +====hi==== +hi"; +$Text = NEW TEXT; +echo $Text->full_format($Str); +echo "\n" +*/ +?> diff --git a/classes/class_time.php b/classes/class_time.php new file mode 100644 index 00000000..f955ef16 --- /dev/null +++ b/classes/class_time.php @@ -0,0 +1,173 @@ +0 && $Levels>0) { + if ($Years>1) { + $Return .= $Years.' years'; + } else { + $Return .= $Years.' year'; + } + $Levels--; + } + + if ($Months>0 && $Levels>0) { + if ($Return!='') { + $Return.=', '; + } + if ($Months>1) { + $Return.=$Months.' months'; + } else { + $Return.=$Months.' month'; + } + $Levels--; + } + + if ($Weeks>0 && $Levels>0) { + if ($Return!="") { + $Return.=', '; + } + if ($Weeks>1) { + $Return.=$Weeks.' weeks'; + } else { + $Return.=$Weeks.' week'; + } + $Levels--; + } + + if ($Days>0 && $Levels>0) { + if ($Return!='') { + $Return.=', '; + } + if ($Days>1) { + $Return.=$Days.' days'; + } else { + $Return.=$Days.' day'; + } + $Levels--; + } + + if ($Hours>0 && $Levels>0) { + if ($Return!='') { + $Return.=', '; + } + if ($Hours>1) { + $Return.=$Hours.' hours'; + } else { + $Return.=$Hours.' hour'; + } + $Levels--; + } + + if ($Minutes>0 && $Levels>0) { + if ($Return!='') { + $Return.=' and '; + } + if ($Minutes>1) { + $Return.=$Minutes.' mins'; + } else { + $Return.=$Minutes.' min'; + } + $Levels--; + } + + if($Return == '') { + $Return = 'Just now'; + } elseif (!isset($HideAgo)) { + $Return .= ' ago'; + } + + if ($Lowercase) { + $Return = strtolower($Return); + } + + if ($Span) { + return ''.$Return.''; + } else { + return $Return; + } +} + +/* SQL utility functions */ + +function time_plus($Offset) { + return date('Y-m-d H:i:s', time()+$Offset); +} + +function time_minus($Offset, $Fuzzy = false) { + if($Fuzzy) { + return date('Y-m-d 00:00:00', time()-$Offset); + } else { + return date('Y-m-d H:i:s', time()-$Offset); + } +} + +function sqltime($timestamp = false) { + if ($timestamp === false) { + $timestamp = time(); + } + return date('Y-m-d H:i:s', $timestamp); +} + +function validDate($DateString) { + $DateTime = explode(" ", $DateString); + if(count($DateTime) != 2) return false; + list($Date, $Time) = $DateTime; + $SplitTime = explode(":", $Time); + if(count($SplitTime) != 3) return false; + list($H, $M, $S) = $SplitTime; + if($H != 0 && !(is_number($H) && $H < 24 && $H >= 0)) return false; + if($M != 0 && !(is_number($M) && $M < 60 && $M >= 0)) return false; + if($S != 0 && !(is_number($S) && $S < 60 && $S >= 0)) return false; + $SplitDate = explode("-", $Date); + if(count($SplitDate) != 3) return false; + list($Y, $M, $D) = $SplitDate; + return checkDate($M, $D, $Y); +} +?> diff --git a/classes/class_torrent.php b/classes/class_torrent.php new file mode 100644 index 00000000..8e9b8251 --- /dev/null +++ b/classes/class_torrent.php @@ -0,0 +1,307 @@ +Str = $Val; + $this->dec(); + } else { + $this->Val = $Val; + } + } + + // Decode an element based on the type. The type is really just an indicator. + function decode($Type, $Key){ + if(is_number($Type)) { // Element is a string + // Get length of string + $StrLen = $Type; + while($this->Str[$this->Pos+1]!=':'){ + $this->Pos++; + $StrLen.=$this->Str[$this->Pos]; + } + $this->Val[$Key] = substr($this->Str, $this->Pos+2, $StrLen); + + $this->Pos+=$StrLen; + $this->Pos+=2; + + } elseif($Type == 'i') { // Element is an int + $this->Pos++; + + // Find end of integer (first occurance of 'e' after position) + $End = strpos($this->Str, 'e', $this->Pos); + + // Get the integer, and - IMPORTANT - cast it as an int, so we know later that it's an int and not a string + $this->Val[$Key] = (int)substr($this->Str, $this->Pos, $End-$this->Pos); + $this->Pos = $End+1; + + } elseif($Type == 'l') { // Element is a list + $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos)); + $this->Pos += $this->Val[$Key]->Pos; + + } elseif($Type == 'd') { // Element is a dictionary + $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos)); + $this->Pos += $this->Val[$Key]->Pos; + // Sort by key to respect spec + ksort($this->Val[$Key]->Val); + + } else { + die('Invalid torrent file'); + } + } + + function encode($Val){ + if(is_int($Val)) { // Integer + return 'i'.$Val.'e'; + } elseif(is_string($Val)) { + return strlen($Val).':'.$Val; + } elseif(is_object($Val)) { + return $Val->enc(); + } else { + return 'fail'; + } + } +} + +class BENCODE_LIST extends BENCODE { + function enc(){ + $Str = 'l'; + reset($this->Val); + foreach ($this->Val as $Value) { + $Str.=$this->encode($Value); + } + return $Str.'e'; + } + + // Decode a list + function dec(){ + $Key = 0; // Array index + $Length = strlen($this->Str); + while($this->Pos<$Length){ + $Type = $this->Str[$this->Pos]; + // $Type now indicates what type of element we're dealing with + // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list) + + if($Type == 'e') { // End of list + $this->Pos += 1; + unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster. + return; + } + + // Decode the bencoded element. + // This function changes $this->Pos and $this->Val, so you don't have to. + $this->decode($Type, $Key); + ++ $Key; + } + return true; + } +} + +class BENCODE_DICT extends BENCODE { + function enc(){ + $Str = 'd'; + reset($this->Val); + foreach ($this->Val as $Key => $Value) { + $Str.=strlen($Key).':'.$Key.$this->encode($Value); + } + return $Str.'e'; + } + + // Decode a dictionary + function dec(){ + $Length = strlen($this->Str); + while($this->Pos<$Length) { + + if($this->Str[$this->Pos] == 'e') { // End of dictionary + $this->Pos += 1; + unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster. + return; + } + + // Get the dictionary key + // Length of the key, in bytes + $KeyLen = $this->Str[$this->Pos]; + + // Allow for multi-digit lengths + while($this->Str[$this->Pos+1]!=':' && $this->Pos+1<$Length) { + $this->Pos++; + $KeyLen.=$this->Str[$this->Pos]; + } + // $this->Pos is now on the last letter of the key length + // Adding 2 brings it past that character and the ':' to the beginning of the string + $this->Pos+=2; + + // Get the name of the key + $Key = substr($this->Str, $this->Pos, $KeyLen); + + // Move the position past the key to the beginning of the element + $this->Pos+=$KeyLen; + $Type = $this->Str[$this->Pos]; + // $Type now indicates what type of element we're dealing with + // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list) + + // Decode the bencoded element. + // This function changes $this->Pos and $this->Val, so you don't have to. + $this->decode($Type, $Key); + + + } + return true; + } +} + + +class TORRENT extends BENCODE_DICT { + function dump() { + // Convenience function used for testing and figuring out how we store the data + print_r($this->Val); + } + + function dump_data() { + // Function which serializes $this->Val for storage + return base64_encode(serialize($this->Val)); + } + + /* + To use this, please remove the announce-list unset in make_private and be sure to still set_announce_url for backwards compatibility + function set_multi_announce() { + $Trackers = func_get_args(); + $AnnounceList = new BENCODE_LIST(array(),true); + foreach ($Trackers as $Tracker) { + $SubList = new BENCODE_LIST(array($Tracker),true); + unset($SubList->Str); + $AnnounceList->Val[] = $SubList; + } + $this->Val['announce-list'] = $AnnounceList; + } + */ + + function set_announce_url($Announce) { + $this->Val['announce'] = $Announce; + } + + // Returns an array of: + // * the files in the torrent + // * the total size of files described therein + function file_list() { + $FileList = array(); + if(!$this->Val['info']->Val['files']) { // Single file mode + $TotalSize = $this->Val['info']->Val['length']; + $FileList[]= array($this->Val['info']->Val['length'], $this->Val['info']->Val['name']); + } else { // Multiple file mode + $FileNames = array(); + $TotalSize = 0; + $Files = $this->Val['info']->Val['files']->Val; + foreach($Files as $File) { + $TotalSize+=$File->Val['length']; + $FileSize = $File->Val['length']; + + $FileName = ltrim(implode('/',$File->Val['path']->Val), '/'); + + $FileList[] = array($FileSize, $FileName); + $FileNames[] = $FileName; + } + array_multisort($FileNames, $FileList); + } + return array($TotalSize, $FileList); + } + + function make_private() { + //----- The following properties do not affect the infohash: + + // anounce-list is an unofficial extension to the protocol + // that allows for multiple trackers per torrent + unset($this->Val['announce-list']); + + // Bitcomet & Azureus cache peers in here + unset($this->Val['nodes']); + + // Azureus stores the dht_backup_enable flag here + unset($this->Val['azureus_properties']); + + // Remove web-seeds + unset($this->Val['url-list']); + + // Remove libtorrent resume info + unset($this->Val['libtorrent_resume']); + + //----- End properties that do not affect the infohash + if ($this->Val['info']->Val['private']) { + return true; // Torrent is private + } else { + // Torrent is not private! + // add private tracker flag and sort info dictionary + $this->Val['info']->Val['private'] = 1; + ksort($this->Val['info']->Val); + return false; + } + } +} + +?> diff --git a/classes/class_torrent_32bit.php b/classes/class_torrent_32bit.php new file mode 100644 index 00000000..78bdff75 --- /dev/null +++ b/classes/class_torrent_32bit.php @@ -0,0 +1,298 @@ +Str = $Val; + $this->dec(); + } + + // Decode an element based on the type + function decode($Type, $Key){ + if(ctype_digit($Type)) { // Element is a string + // Get length of string + $StrLen = $Type; + while($this->Str[$this->Pos+1]!=':'){ + $this->Pos++; + $StrLen.=$this->Str[$this->Pos]; + } + $this->Val[$Key] = substr($this->Str, $this->Pos+2, $StrLen); + + $this->Pos+=$StrLen; + $this->Pos+=2; + + } elseif($Type == 'i') { // Element is an int + $this->Pos++; + + // Find end of integer (first occurance of 'e' after position) + $End = strpos($this->Str, 'e', $this->Pos); + + // Get the integer, and mark it as an int (on our version 64 bit box, we cast it to an int) + $this->Val[$Key] = '[*INT*]'.substr($this->Str, $this->Pos, $End-$this->Pos); + $this->Pos = $End+1; + + } elseif($Type == 'l') { // Element is a list + $this->Val[$Key] = new BENCODE_LIST(substr($this->Str, $this->Pos)); + $this->Pos += $this->Val[$Key]->Pos; + + } elseif($Type == 'd') { // Element is a dictionary + $this->Val[$Key] = new BENCODE_DICT(substr($this->Str, $this->Pos)); + $this->Pos += $this->Val[$Key]->Pos; + // Sort by key to respect spec + ksort($this->Val[$Key]->Val); + + } else { + die('Invalid torrent file'); + } + } + + function encode($Val){ + if(is_string($Val)) { + if(substr($Val, 0, 7) == '[*INT*]') { + return 'i'.substr($Val,7).'e'; + } else { + return strlen($Val).':'.$Val; + } + } elseif(is_object($Val)) { + return $Val->enc(); + } else { + return 'fail'; + } + } +} + +class BENCODE_LIST extends BENCODE { + function enc(){ + $Str = 'l'; + reset($this->Val); + while(list($Key, $Value) = each($this->Val)) { + $Str.=$this->encode($Value); + } + return $Str.'e'; + } + + // Decode a list + function dec(){ + $Key = 0; // Array index + $Length = strlen($this->Str); + while($this->Pos<$Length){ + $Type = $this->Str[$this->Pos]; + // $Type now indicates what type of element we're dealing with + // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list) + + if($Type == 'e') { // End of list + $this->Pos += 1; + unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster. + return; + } + + // Decode the bencoded element. + // This function changes $this->Pos and $this->Val, so you don't have to. + $this->decode($Type, $Key); + ++ $Key; + } + return true; + } +} + +class BENCODE_DICT extends BENCODE { + function enc(){ + $Str = 'd'; + reset($this->Val); + while(list($Key, $Value) = each($this->Val)) { + $Str.=strlen($Key).':'.$Key.$this->encode($Value); + } + return $Str.'e'; + } + + // Decode a dictionary + function dec(){ + $Length = strlen($this->Str); + while($this->Pos<$Length) { + + if($this->Str[$this->Pos] == 'e') { // End of dictionary + $this->Pos += 1; + unset($this->Str); // Since we're finished parsing the string, we don't need to store it anymore. Benchmarked - this makes the parser run way faster. + return; + } + + // Get the dictionary key + // Length of the key, in bytes + $KeyLen = $this->Str[$this->Pos]; + + // Allow for multi-digit lengths + while($this->Str[$this->Pos+1]!=':' && $this->Pos+1<$Length) { + $this->Pos++; + $KeyLen.=$this->Str[$this->Pos]; + } + // $this->Pos is now on the last letter of the key length + // Adding 2 brings it past that character and the ':' to the beginning of the string + $this->Pos+=2; + + // Get the name of the key + $Key = substr($this->Str, $this->Pos, $KeyLen); + + // Move the position past the key to the beginning of the element + $this->Pos+=$KeyLen; + $Type = $this->Str[$this->Pos]; + // $Type now indicates what type of element we're dealing with + // It's either an integer (string), 'i' (an integer), 'l' (a list), 'd' (a dictionary), or 'e' (end of dictionary/list) + + // Decode the bencoded element. + // This function changes $this->Pos and $this->Val, so you don't have to. + $this->decode($Type, $Key); + + + } + return true; + } +} + + +class TORRENT extends BENCODE_DICT { + function dump() { + // Convenience function used for testing and figuring out how we store the data + print_r($this->Val); + } + + function dump_data() { + // Function which serializes $this->Val for storage + return base64_encode(serialize($this->Val)); + } + + function set_announce_url($Announce) { + $this->Val['announce'] = $Announce; + } + + // Returns an array of: + // * the files in the torrent + // * the total size of files described therein + function file_list() { + $FileList = array(); + if(!$this->Val['info']->Val['files']) { // Single file mode + $TotalSize = substr($this->Val['info']->Val['length'],7); + $FileList[]= array($TotalSize, $this->Val['info']->Val['name']); + } else { // Multiple file mode + $TotalSize = 0; + $Files = $this->Val['info']->Val['files']->Val; + foreach($Files as $File) { + $TotalSize+=substr($File->Val['length'], 7); + $FileSize = substr($File->Val['length'],7); + + $FileName = implode('/',$File->Val['path']->Val); + + $FileList[]=array($FileSize, $FileName); + + } + } + return array($TotalSize, $FileList); + } + + function make_private() { + //----- The following properties do not affect the infohash: + + // anounce-list is an unofficial extension to the protocol + // that allows for multiple trackers per torrent + unset($this->Val['announce-list']); + + // Bitcomet & Azureus cache peers in here + unset($this->Val['nodes']); + + // Azureus stores the dht_backup_enable flag here + unset($this->Val['azureus_properties']); + + // Remove web-seeds + unset($this->Val['url-list']); + + // Remove libtorrent resume info + unset($this->Val['libtorrent_resume']); + + //----- End properties that do not affect the infohash + + if (!empty($this->Val['info']->Val['private']) && $this->Val['info']->Val['private'] == '[*INT*]1') { + return true; + } else { + // Torrent is not private! + // add private tracker flag and sort info dictionary + $this->Val['info']->Val['private'] = '[*INT*]1'; + ksort($this->Val['info']->Val); + return false; + } + } +} +?> diff --git a/classes/class_torrent_form.php b/classes/class_torrent_form.php new file mode 100644 index 00000000..7234e48d --- /dev/null +++ b/classes/class_torrent_form.php @@ -0,0 +1,713 @@ +NewTorrent = $NewTorrent; + $this->Torrent = $Torrent; + $this->Error = $Error; + + global $Categories, $Formats, $Bitrates, $Media, $TorrentID; + + $this->Categories = $Categories; + $this->Formats = $Formats; + $this->Bitrates = $Bitrates; + $this->Media = $Media; + $this->TorrentID = $TorrentID; + + if($this->Torrent && $this->Torrent['GroupID']) { + $this->Disabled = ' disabled="disabled"'; + } + } + + + function head() { + global $LoggedUser; +?> +
    +NewTorrent) { ?> +

    + Your personal announce url is:
    + +

    +Error) { + echo '

    '.$this->Error.'

    '; + } +?> +
    +
    + + +NewTorrent) { ?> + + + +Torrent && $this->Torrent['GroupID']) { ?> + + +Torrent && $this->Torrent['RequestID']) { ?> + + +
    +NewTorrent) { ?> + + + + + + + + + +
    + Torrent file + + +
    + Type + + +
    + +
    +Torrent; +?> +
    + + +NewTorrent) { + if(check_perms('torrents_freeleech')) { +?> + + + + + + + + +
    Freeleech + + because + +
    +

    Be sure that your torrent is approved by the rules. Not doing this will result in a warning or worse.

    +NewTorrent) { ?> +

    After uploading the torrent, you will have a one hour grace period during which no one other than you can fill requests with this torrent. Make use of this time wisely, and search the requests.

    + + NewTorrent) { echo "value=\"Upload torrent\""; } else { echo "value=\"Edit torrent\"";} ?> /> +
    +
    +
    +Torrent; + $IsRemaster = !empty($Torrent['Remastered']); + $UnknownRelease = !$this->NewTorrent && $IsRemaster && !$Torrent['RemasterYear']; + + if($Torrent['GroupID']) { + global $DB; + $DB->query("SELECT ID, + RemasterYear, + RemasterTitle, + RemasterRecordLabel, + RemasterCatalogueNumber + FROM torrents + WHERE GroupID = ".$Torrent['GroupID']." + AND Remastered = '1' + AND RemasterYear != 0 + ORDER BY RemasterYear DESC, + RemasterTitle DESC, + RemasterRecordLabel DESC, + RemasterCatalogueNumber DESC"); + + if($DB->record_count() > 0) { + $GroupRemasters = $DB->to_array(false, MYSQLI_BOTH, false); + } + } + + $HasLog = $Torrent['HasLog']; + $HasCue = $Torrent['HasCue']; + $BadTags = $Torrent['BadTags']; + $BadFolders = $Torrent['BadFolders']; + $BadFiles = $Torrent['BadFiles']; + $CassetteApproved = $Torrent['CassetteApproved']; + $LossymasterApproved = $Torrent['LossymasterApproved']; + global $ReleaseTypes; +?> + +NewTorrent) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NewTorrent) { ?> + + + + + + + + + +NewTorrent) { ?> + + + + + +NewTorrent && check_perms('users_mod')) { ?> + + + + + + +NewTorrent && check_perms('users_mod')) {?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NewTorrent) { ?> + + + + + + + + + + + + + + + + + +
    Artist(s) + + $Artists) { + foreach($Artists as $Artist) { +?> + Disabled?>/> + + + [+] [-] + +
    + + Disabled?>/> + + [+] [-] + +
    Album title: + Disabled?>/> +

    Do not include the words remaster, re-issue, MSFL Gold, limited edition, bonus tracks, bonus disc or country specific information in this field. That belongs in the edition information fields below, see this for further information. Also remember to use the correct capitalization for your upload. See the Capitalization Guidelines for more information. +

    + + + + + Disabled?> onblur="CheckYear();" /> This is the year of the original release. +
    Record Label (Optional): + Disabled?> /> +
    Catalogue Number (Optional): + Disabled?> /> +
    + Release Type + + Please take the time to fill this out properly (try searching MusicBrainz). +
    Edition Information + onclick="Remaster();NewTorrent) {?> CheckYear();" /> + Check this box if this torrent is a different release to the original, for example a limited or country specific edition or a release that includes additional bonus tracks or is a bonus disc. + +
    Scene + /> + Check this only if this is a 'scene release'. If you ripped it yourself, it is not a scene release.
    If you are not sure, DO NOT check it, you will be penalized. For information on the scene, visit Wikipedia. +
    Format + +
    Bit Rate + + +
    Vanity House + +
    Media + + +
    Log/Cue + /> Check this box if the torrent has (or should have) a log file.
    + /> Check this box if the torrent has (or should have) a cue file.
    +query("SELECT LogID FROM torrents_logs_new where TorrentID = ".$this->TorrentID." AND Log LIKE 'EAC extraction logfile%' AND (Adjusted = '0' OR Adjusted = '')"); + list($LogID) = $DB->next_record(); + if ($LogID) { + if (!check_perms('users_mod')) { +?> +
    Trumpable + + /> Check this box if you want this torrent to be trumpable (subtracts 1 point). +
    Log Score + +
    Log Adjustment Reason + +

    Contains reason for adjusting a score. This field is displayed on the torrent page.

    +
    Bad Tags + /> Check this box if the torrent has bad tags. +
    Bad Folder Names + /> Check this box if the torrent has bad folder names. +
    Bad File Names + /> Check this box if the torrent has bad file names. +
    Cassette Approved + /> Check this box if the torrent is an approved cassette rip. +
    Lossy master Approved + /> Check this box if the torrent is an approved lossy master. +
    Tags + + + + Disabled?>/> +
    + Tags should be comma separated, and you should use a period ('.') to separate words inside a tag - eg. 'hip.hop'. +

    + There is a list of official tags to the left of the text box. Please use these tags instead of 'unofficial' tags (e.g. use the official 'drum.and.bass' tag, instead of an unofficial 'dnb' tag). Please note that the '2000s' tag refers to music produced between 2000 and 2009. +

    + Avoid abbreviations if at all possible. So instead of tagging an album as 'alt', tag it as 'alternative'. Make sure that you use correct spelling. +

    + Avoid using multiple synonymous tags. Using both 'prog.rock' and 'progressive.rock' is redundant and annoying - just use the official 'progressive.rock' tag. +

    + Don't use 'useless' tags, such as 'seen.live', 'awesome', 'rap' (is encompassed by 'hip.hop'), etc. If an album is live, you can tag it as 'live'. +

    + Only tag information on the album itself - NOT THE INDIVIDUAL RELEASE. Tags such as 'v0', 'eac', 'vinyl', 'from.oink' etc. are strictly forbidden. Remember that these tags will be used for other versions of the same album. +

    + You should be able to build up a list of tags using only the official tags to the left of the text box. If you are in any doubt about whether or not a tag is acceptable, do not add it. +
    Image (optional) + Disabled?>/> +
    Album Description + +

    Contains background information such as album history and maybe a review.

    +
    Release Description (optional) + +

    Contains information like encoder settings or details of the ripping process. DO NOT PASTE THE RIPPING LOG HERE.

    +
    +Torrent; +?> + +NewTorrent){ ?> + + + + + + + + + + + + + + + + + +NewTorrent) { ?> + + + + + + + + + + + + + + + + + +
    Author - Title + +

    Should only include the author if applicable

    +
    Year + +
    Format + +
    Bitrate + + +
    Tags + +
    Image (optional) + Disabled?>/> +
    Description + +

    Contains information like the track listing, and maybe a review.

    +
    Release Description (optional) + +

    Contains information like encoder settings, and/or a log of the ripping process.

    +
    +Torrent; +?> + +NewTorrent) { + if ($this->Categories[$CategoryID] == 'E-Books') { ?> + + + + + + + + + + + + + + + + + + + + +
    Author - TitleTitle + +
    Tags + +
    Image (optional) + Disabled?>/> +
    Description + +
    + diff --git a/classes/class_user_rank.php b/classes/class_user_rank.php new file mode 100644 index 00000000..0c0613b8 --- /dev/null +++ b/classes/class_user_rank.php @@ -0,0 +1,107 @@ +query("DROP TEMPORARY TABLE IF EXISTS temp_stats"); + + $DB->query("CREATE TEMPORARY TABLE temp_stats + (ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT, + Val bigint(20) NOT NULL);"); + + $DB->query("INSERT INTO temp_stats (Val) ".$Query); + + $DB->query("SELECT COUNT(ID) FROM temp_stats"); + list($UserCount) = $DB->next_record(); + + $DB->query("SELECT MIN(Val) FROM temp_stats GROUP BY CEIL(ID/(".(int)$UserCount."/100));"); + + $Table = $DB->to_array(); + + // Give a little variation to the cache length, so all the tables don't expire at the same time + $Cache->cache_value($MemKey, $Table, 3600*24*rand(800,1000)*0.001); + + return $Table; + } + + function table_query($TableName) { + switch($TableName) { + case 'uploaded': + $Query = "SELECT Uploaded FROM users_main WHERE Enabled='1' AND Uploaded>0 ORDER BY Uploaded;"; + break; + case 'downloaded': + $Query = "SELECT Downloaded FROM users_main WHERE Enabled='1' AND Downloaded>0 ORDER BY Downloaded;"; + break; + case 'uploads': + $Query = "SELECT COUNT(t.ID) AS Uploads FROM users_main AS um JOIN torrents AS t ON t.UserID=um.ID WHERE um.Enabled='1' GROUP BY um.ID ORDER BY Uploads;"; + break; + case 'requests': + $Query = "SELECT COUNT(r.ID) AS Requests FROM users_main AS um JOIN requests AS r ON r.FillerID=um.ID WHERE um.Enabled='1' GROUP BY um.ID ORDER BY Requests;"; + break; + case 'posts': + $Query = "SELECT COUNT(p.ID) AS Posts FROM users_main AS um JOIN forums_posts AS p ON p.AuthorID=um.ID WHERE um.Enabled='1' GROUP BY um.ID ORDER BY Posts;"; + break; + case 'bounty': + //Request bunny exception + $Query = "SELECT SUM(rv.Bounty) AS Bounty FROM users_main AS um JOIN requests_votes AS rv ON rv.UserID=um.ID WHERE um.Enabled='1' AND um.ID <> 260542 GROUP BY um.ID ORDER BY Bounty;"; + break; + case 'artists': + $Query = "SELECT COUNT(ta.ArtistID) AS Artists FROM torrents_artists AS ta JOIN torrents_group AS tg ON tg.ID=ta.GroupID JOIN torrents AS t ON t.GroupID = tg.ID WHERE t.UserID != ta.UserID GROUP BY tg.ID ORDER BY Artists ASC"; + break; + } + return $Query; + } + + function get_rank($TableName, $Value) { + if($Value == 0) { return 0; } + global $Cache, $DB; + + $Table = $Cache->get_value(PREFIX.$TableName); + if(!$Table) { + //Cache lock! + $Lock = $Cache->get_value(PREFIX.$TableName."_lock"); + if($Lock) { + ?>cache_value(PREFIX.$TableName."_lock", '1', 10); + $Table = $this->build_table(PREFIX.$TableName, $this->table_query($TableName)); + } + } + $LastPercentile = 0; + foreach ($Table as $Row) { + list($CurValue) = $Row; + if($CurValue>=$Value) { + return $LastPercentile; + } + $LastPercentile++; + } + return 100; // 100th percentile + } + + function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio){ + // We can do this all in 1 line, but it's easier to read this way + if($Ratio>1) { $Ratio = 1; } + $TotalScore = 0; + $TotalScore += $Uploaded*15; + $TotalScore += $Downloaded*8; + $TotalScore += $Uploads*25; + $TotalScore += $Requests*2; + $TotalScore += $Posts; + $TotalScore += $Bounty; + $TotalScore += $Artists; + $TotalScore /= (15+8+25+2+1+1+1); + $TotalScore *= $Ratio; + return $TotalScore; + + } + +} + + +?> diff --git a/classes/class_useragent.php b/classes/class_useragent.php new file mode 100644 index 00000000..eb7185ad --- /dev/null +++ b/classes/class_useragent.php @@ -0,0 +1,151 @@ + 'Shiira', + 'Songbird' => 'Songbird', + 'SeaMonkey' => 'SeaMonkey', + 'OmniWeb' => 'OmniWeb', + 'Camino' => 'Camino', + 'Chimera' => 'Chimera', + 'Epiphany' => 'Epiphany', + 'Konqueror' => 'Konqueror', + 'Iceweasel' => 'Iceweasel', + 'Lynx' => 'Lynx', + 'Links' => 'Links', + 'libcurl' => 'cURL', + 'midori' => 'Midori', + 'Blackberry' => 'Blackberry Browser', + //Big names + 'Firefox' => 'Firefox', + 'Chrome' => 'Chrome', + 'Safari' => 'Safari', + 'Opera' => 'Opera', + //Put chrome frame above IE + 'chromeframe' => 'Chrome Frame', + 'x-clock' => 'Chrome Frame', + 'MSIE' => 'Internet Explorer', + //Firefox versions + 'Shiretoko' => 'Firefox (Experimental)', + 'Minefield' => 'Firefox (Experimental)', + 'GranParadiso' => 'Firefox (Experimental)', + 'Namoroka' => 'Firefox (Experimental)', + 'AppleWebKit' => 'WebKit', + 'Mozilla' => 'Mozilla' + //Weird shit + /* + 'WWW-Mechanize' => 'Perl', + 'Wget' => 'Wget', + 'BTWebClient' => 'µTorrent', + 'Transmission' => 'Transmission', + 'Java' => 'Java', + 'RSS' => 'RSS Downloader' + */ + ); + + var $OperatingSystems = array( + //Mobile + 'SymbianOS' => 'Symbian', + 'blackberry' => 'BlackBerry', + 'iphone' => 'iPhone', + 'ipod' => 'iPhone', + 'android' => 'Android', + 'palm' => 'Palm', + 'mot-razr' => 'Motorola Razr', + //Windows + 'Windows NT 6.1' => 'Windows 7', + 'Windows 7' => 'Windows 7', + 'Windows NT 6.0' => 'Windows Vista', + 'Windows Vista' => 'Windows Vista', + 'windows nt 5.2' => 'Windows 2003', + 'windows 2003' => 'Windows 2003', + 'windows nt 5.0' => 'Windows 2000', + 'windows 2000' => 'Windows 2000', + 'windows nt 5.1' => 'Windows XP', + 'windows xp' => 'Windows XP', + 'Win 9x 4.90' => 'Windows ME', + 'Windows Me' => 'Windows ME', + 'windows nt' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'windows ce' => 'Windows CE', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'win16' => 'Windows 3.1', + //'windows' => 'Windows', + //OS X + 'os x' => 'Mac OS X', + 'macintosh' => 'Mac OS X', + 'darwin' => 'Mac OS X', + //Less popular + 'ubuntu' => 'Ubuntu', + 'debian' => 'Debian', + 'fedora' => 'Fedora', + 'freebsd' => 'FreeBSD', + 'openbsd' => 'OpenBSD', + 'bsd' => 'BSD', + 'x11' => 'Linux', + 'gnu' => 'Linux', + 'linux' => 'Linux', + 'unix' => 'Unix', + 'Sun OS' => 'Sun', + 'Sun' => 'Sun', + //Weird shit + /* + 'WWW-Mechanize' => 'Perl', + 'Wget' => 'Wget', + 'BTWebClient' => 'µTorrent', + 'Transmission' => 'Transmission', + 'Java' => 'Java', + 'RSS' => 'RSS Downloader', + */ + //Catch-all + 'win' => 'Windows', + 'mac' => 'Mac OS X' + ); + + public function operating_system(&$UserAgentString) { + if (empty($UserAgentString)) { + return 'Hidden'; + } + $Return = 'Unknown'; + foreach ($this->OperatingSystems as $String => $OperatingSystem) { + if (stripos($UserAgentString, $String) !== false) { + $Return = $OperatingSystem; + break; + } + } + return $Return; + } + + public function mobile(&$UserAgentString) { + if (strpos($UserAgentString, 'iPad')) { + return false; + } + + //Mobi catches Mobile + if (/*strpos($UserAgentString, 'Mobile') || */strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) { + return true; + } + return false; + } + + public function browser(&$UserAgentString) { + if (empty($UserAgentString)) { + return 'Hidden'; + } + $Return = 'Unknown'; + foreach ($this->Browsers as $String => $Browser) { + if (strpos($UserAgentString, $String) !== false) { + $Return = $Browser; + break; + } + } + if($this->mobile($UserAgentString)) { + $Return .= ' Mobile'; + } + return $Return; + } +} diff --git a/classes/class_validate.php b/classes/class_validate.php new file mode 100644 index 00000000..499d83f5 --- /dev/null +++ b/classes/class_validate.php @@ -0,0 +1,187 @@ +Fields[$FieldName]['Type']=strtolower($FieldType); + $this->Fields[$FieldName]['Required']=$Required; + $this->Fields[$FieldName]['ErrorMessage']=$ErrorMessage; + if(!empty($Options['maxlength'])) { + $this->Fields[$FieldName]['MaxLength']=$Options['maxlength']; + } + if(!empty($Options['minlength'])) { + $this->Fields[$FieldName]['MinLength']=$Options['minlength']; + } + if(!empty($Options['comparefield'])) { + $this->Fields[$FieldName]['CompareField']=$Options['comparefield']; + } + if(!empty($Options['allowperiod'])) { + $this->Fields[$FieldName]['AllowPeriod']=$Options['allowperiod']; + } + if(!empty($Options['allowcomma'])) { + $this->Fields[$FieldName]['AllowComma']=$Options['allowcomma']; + } + if(!empty($Options['inarray'])) { + $this->Fields[$FieldName]['InArray']=$Options['inarray']; + } + if(!empty($Options['regex'])) { + $this->Fields[$FieldName]['Regex']=$Options['regex']; + } + } + + function ValidateForm($ValidateArray) { + reset($this->Fields); + foreach ($this->Fields as $FieldKey => $Field) { + $ValidateVar=$ValidateArray[$FieldKey]; + + if($ValidateVar!="" || !empty($Field['Required']) || $Field['Type']=="date") { + if($Field['Type']=="string") { + if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=255; } + if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=1; } + + if(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="number") { + if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=''; } + if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=0; } + + $Match='0-9'; + if(isset($Field['AllowPeriod'])) { $Match.='.'; } + if(isset($Field['AllowComma'])) { $Match.=','; } + + if(preg_match('/[^'.$Match.']/', $ValidateVar) || strlen($ValidateVar)<1) { return $Field['ErrorMessage']; } + elseif($MaxLength!="" && $ValidateVar>$MaxLength) { return $Field['ErrorMessage']."!!"; } + elseif($ValidateVar<$MinLength) { return $Field['ErrorMessage']."$MinLength"; } + + } elseif($Field['Type']=="email") { + if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=255; } + if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=6; } + + if(!preg_match("/^".EMAIL_REGEX."$/i", $ValidateVar)) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="link") { + if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=255; } + if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=10; } + + if(!preg_match('/^(https?):\/\/([a-z0-9\-\_]+\.)+([a-z]{1,5}[^\.])(\/[^<>]+)*$/i', $ValidateVar)) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="username") { + if(isset($Field['MaxLength'])) { $MaxLength=$Field['MaxLength']; } else { $MaxLength=20; } + if(isset($Field['MinLength'])) { $MinLength=$Field['MinLength']; } else { $MinLength=1; } + + if(preg_match('/[^a-z0-9_\-?]/i', $ValidateVar)) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)>$MaxLength) { return $Field['ErrorMessage']; } + elseif(strlen($ValidateVar)<$MinLength) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="checkbox") { + if(!isset($ValidateArray[$FieldKey])) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="compare") { + if($ValidateArray[$Field['CompareField']]!=$ValidateVar) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="inarray") { + if(array_search($ValidateVar, $Field['InArray'])===false) { return $Field['ErrorMessage']; } + + } elseif($Field['Type']=="regex") { + if(!preg_match($Field['Regex'], $ValidateVar)) { return $Field['ErrorMessage']; } + } + } + } // while + } // function + + function GenerateJS($FormID) { + $ReturnJS="\r\n"; + return $ReturnJS; + } +} +?> diff --git a/classes/class_wiki.php b/classes/class_wiki.php new file mode 100644 index 00000000..17525980 --- /dev/null +++ b/classes/class_wiki.php @@ -0,0 +1,86 @@ +Table = $Table; + $this->PageID = $PageID; + $this->BaseURL = $BaseURL; + } + + function revision_history(){ + global $DB; + + $BaseURL = $this->BaseURL; + $DB->query("SELECT + RevisionID, + Summary, + Time, + UserID, + users.Username + FROM ".$this->Table." AS wiki + JOIN users_main AS users ON users.ID = wiki.UserID + WHERE wiki.PageID = ".$this->PageID." + ORDER BY RevisionID DESC"); +//----------------------------------------------- ?> + + + + + +next_record()){ + $Row = ($Row == 'a') ? 'b' : 'a'; +//------------------------------------------------------ ?> + + + + + +
    RevisionSummary
    + #$RevisionID" ?> + + + Edited by + Reason: +
    + \ No newline at end of file diff --git a/classes/class_zip.php b/classes/class_zip.php new file mode 100644 index 00000000..d9cddfe9 --- /dev/null +++ b/classes/class_zip.php @@ -0,0 +1,184 @@ +unlimit(); + + A simple shortcut function for raising the basic PHP limits, time and memory for larger archives. + +----- + +* Then, add files and begin streaming to the user to avoid memory buffering: + +$Zip->add_file(file_get_contents("data/file.txt"), "File.txt"); + + Adds the contents of data/file.txt into File.txt in the archive root. + +$Zip->add_file($TorrentData, "Bookmarks/Artist - Album [2008].torrent"); + + Adds the parsed torrent to the archive in the Bookmarks folder (created simply by placing it in the path). + +----- + +* Then, close the archive to the user: + +$Zip->close_stream(); + + This collects everything put together thus far in the archive, and streams it to the user in the form of Test7.zip + +//------ Explanation of basic functions ------// + +add_file(Contents, Internal Path) + Adds the contents to the archive, where it will be extracted to Internal Path. + +close_stream(); + Collect and stream to the user. + +//------------- Detailed example -------------// + +require('classes/class_zip.php'); +$Zip = new ZIP('FileName'); +$Name = 'Ubuntu-8.10'; +$Zip->add_file($TorrentData, 'Torrents/'.file_string($Name).'.torrent'); +$Zip->add_file(file_get_contents('zip.php'), 'zip.php'); +$Zip->close_stream(); + + +//---------- Development reference -----------// +http://www.pkware.com/documents/casestudies/APPNOTE.TXT - ZIP spec (this class) +http://www.ietf.org/rfc/rfc1950.txt - ZLIB compression spec (gzcompress function) +http://www.fileformat.info/tool/hexdump.htm - Useful for analyzing ZIP files + +|*************************************************************************/ + +if (!extension_loaded('zlib')) { + error('Zlib Extension not loaded.'); +} +/* +//Handles timestamps +function dostime($TimeStamp = 0) { + if(!is_number($TimeStamp)) { // Assume that $TimeStamp is SQL timestamp + if($TimeStamp == '0000-00-00 00:00:00') { return 'Never'; } + $TimeStamp = strtotime($TimeStamp); + } + $Date = ($TimeStamp == 0) ? getdate() : getdate($TimeStamp); + $Hex = dechex((($Date['year'] - 1980) << 25) | ($Date['mon'] << 21) | ($Date['mday'] << 16) | ($Date['hours'] << 11) | ($Date['minutes'] << 5) | ($Date['seconds'] >> 1)); + eval("\$Return = \"\x$Hex[6]$Hex[7]\x$Hex[4]$Hex[5]\x$Hex[2]$Hex[3]\x$Hex[0]$Hex[1]\";"); + return $Return; +} +*/ + +class ZIP { + public $ArchiveSize = 0; //Total size + public $ArchiveFiles = 0; // Total files + private $Structure = ''; // Structure saved to memory + private $FileOffset = 0; // Offset to write data + private $Data = ''; //An idea + + public function __construct ($ArchiveName='Archive') { + header("Content-type: application/octet-stream"); //Stream download + header("Content-disposition: attachment; filename=\"".urlencode($ArchiveName).".zip\""); //Name the archive + } + + public static function unlimit () { + ob_end_clean(); + set_time_limit(3600); //Limit 1 hour + ini_set('memory_limit', '1024M'); // Because the buffers can get extremely large + } + + public function add_file ($FileData, $ArchivePath, $TimeStamp = 0) { + /* File header */ + $this->Data = "\x50\x4b\x03\x04"; // PK signature + $this->Data .= "\x14\x00"; // Version requirements + $this->Data .= "\x00\x00"; // Bit flag + $this->Data .= "\x08\x00"; // Compression + //$this->Data .= dostime($TimeStamp); //Last modified + $this->Data .= "\x00\x00\x00\x00"; + $DataLength = strlen($FileData); // Saved as varibale to avoid wasting CPU calculating it multiple times. + $CRC32 = crc32($FileData); // Ditto. + $ZipData = gzcompress($FileData); // Ditto. + $ZipData = substr ($ZipData, 2,(strlen($ZipData) - 6)); // Checksum resolution + $ZipLength = strlen($ZipData); //Ditto. + $this->Data .= pack("V",$CRC32); // CRC-32 + $this->Data .= pack("V",$ZipLength); // Compressed filesize + $this->Data .= pack("V",$DataLength); // Uncompressed filesize + $this->Data .= pack("v",strlen($ArchivePath)); // Pathname length + $this->Data .="\x00\x00"; // Extra field length (0'd so we can ignore this) + $this->Data .= $ArchivePath; // Filename & Exta Field (length set to 0 so ignored) + /* END file header */ + + /* File data */ + $this->Data .= $ZipData; // File data + /* END file data */ + + /* Data descriptor + Not needed (only needed when 3rd bitflag is set), causes problems with OS X archive utility + $this->Data .= pack("V",$CRC32); // CRC-32 + $this->Data .= pack("V",$ZipLength); // Compressed filesize + $this->Data .= pack("V",$DataLength); // Uncompressed filesize + END data descriptor */ + + $FileDataLength = strlen($this->Data); + $this->ArchiveSize = $this->ArchiveSize + $FileDataLength; // All we really need is the size + $CurrentOffset = $this->ArchiveSize; // Update offsets + echo $this->Data; // Get this out to reduce our memory consumption + + /* Central Directory Structure */ + $CDS = "\x50\x4b\x01\x02"; // CDS signature + $CDS .="\x00\x00"; // Constructor version + $CDS .="\x14\x00"; // Version requirements + $CDS .="\x00\x00"; // Bit flag + $CDS .="\x08\x00"; // Compression + $CDS .="\x00\x00\x00\x00"; // Last modified + $CDS .= pack("V",$CRC32); // CRC-32 + $CDS .= pack("V",$ZipLength); // Compressed filesize + $CDS .= pack("V",$DataLength); // Uncompressed filesize + $CDS .= pack("v",strlen($ArchivePath)); // Pathname length + $CDS .="\x00\x00"; // Extra field length (0'd so we can ignore this) + $CDS .="\x00\x00"; // File comment length (no comment, 0'd) + $CDS .="\x00\x00"; // Disk number start (0 seems valid) + $CDS .="\x00\x00"; // Internal file attributes (again with the 0's) + $CDS .="\x20\x00\x00\x00"; // External file attributes + $CDS .= pack("V", $this->FileOffset ); // Offsets + $CDS .= $ArchivePath; // Filename & Exta Field (length set to 0 so ignored) + /* END central Directory Structure */ + + $this->FileOffset = $CurrentOffset; // Update offsets + $this->Structure .= $CDS; // Append to structure + $this->ArchiveFiles++; // Increment file count + } + + public function close_stream() { + echo $this->Structure; // Structure Root + echo "\x50\x4b\x05\x06"; // End of central directory signature + echo "\x00\x00"; // This disk + echo "\x00\x00"; // CDS start + echo pack("v", $this->ArchiveFiles); // Handle the numebr of entries + echo pack("v", $this->ArchiveFiles); // Ditto + echo pack("V", strlen($this->Structure)); //Size + echo pack("V", $this->ArchiveSize); // Offset + echo "\x00\x00"; // No comment, close it off + } +} diff --git a/classes/config.template b/classes/config.template new file mode 100644 index 00000000..ebc2dcbd --- /dev/null +++ b/classes/config.template @@ -0,0 +1,188 @@ +'Personal', 1=>'Theme', 2=>'Genre introduction', 3=>'Discography', 4=>'Label', 5=>'Staff picks', 6=>'Charts'); + +$ReleaseTypes = array(1=>'Album', 3=>'Soundtrack', 5=>'EP', 6=>'Anthology', 7=>'Compilation', 9=>'Single', 11=>'Live album', 13=>'Remix', 14=>'Bootleg', 15=>'Interview', 16=>'Mixtape', 21=>'Unknown'); +//$ForumCats = array(1=>'Site', 5=>'Community', 10=>'Help', 8=>'Music', 20=>'Trash'); //No longer needed + +$ZIPGroups = array( + 0 => 'MP3 (VBR) - High Quality', + 1 => 'MP3 (VBR) - Low Quality', + 2 => 'MP3 (CBR)', + 3 => 'FLAC - Lossless', + 4 => 'Others' +); + +//3D array of attributes, OptionGroup, OptionNumber, Name +$ZIPOptions = array( + '00' => array(0,0,'V0'), + '01' => array(0,1,'APX'), + '02' => array(0,2,'256'), + '03' => array(0,3,'V1'), + '10' => array(1,0,'224'), + '11' => array(1,1,'V2'), + '12' => array(1,2,'APS'), + '13' => array(1,3,'192'), + '20' => array(2,0,'320'), + '21' => array(2,1,'256'), + '22' => array(2,2,'224'), + '23' => array(2,3,'192'), + '30' => array(3,0,'FLAC / 24bit / Vinyl'), + '31' => array(3,1,'FLAC / 24bit / DVD'), + '32' => array(3,2,'FLAC / 24bit / SACD'), + '33' => array(3,3,'FLAC / Log (100) / Cue'), + '34' => array(3,4,'FLAC / Log (100)'), + '35' => array(3,5,'FLAC / Log'), + '36' => array(3,6,'FLAC'), + '40' => array(4,0,'DTS'), + '41' => array(4,1,'Ogg Vorbis'), + '42' => array(4,2,'AAC - 320'), + '43' => array(4,3,'AAC - 256'), + '44' => array(4,4,'AAC - q5.5'), + '45' => array(4,5,'AAC - q5'), + '46' => array(4,6,'AAC - 192') +); + +// Ratio requirements, in descending order +// Columns: Download amount, required ratio, grace period +$RatioRequirements = array( + array(50*1024*1024*1024, 0.60, date('Y-m-d H:i:s')), + array(40*1024*1024*1024, 0.50, date('Y-m-d H:i:s')), + array(30*1024*1024*1024, 0.40, date('Y-m-d H:i:s')), + array(20*1024*1024*1024, 0.30, date('Y-m-d H:i:s')), + array(10*1024*1024*1024, 0.20, date('Y-m-d H:i:s')), + array(5*1024*1024*1024, 0.15, date('Y-m-d H:i:s', time()-(60*60*24*14))) +); + +//Captcha fonts should be located in /classes/fonts +$CaptchaFonts=array('ARIBLK.TTF','IMPACT.TTF','TREBUC.TTF','TREBUCBD.TTF','TREBUCBI.TTF','TREBUCIT.TTF','VERDANA.TTF','VERDANAB.TTF','VERDANAI.TTF','VERDANAZ.TTF'); +//Captcha images should be located in /captcha +$CaptchaBGs=array('captcha1.png','captcha2.png','captcha3.png','captcha4.png','captcha5.png','captcha6.png','captcha7.png','captcha8.png','captcha9.png'); + +// Special characters, and what they should be converted to +// Used for torrent searching +$SpecialChars = array( + '&' => 'and' +); +?> diff --git a/classes/fonts/ARIBLK.TTF b/classes/fonts/ARIBLK.TTF new file mode 100644 index 0000000000000000000000000000000000000000..453ecb5fba2d87b65bdebe34b63db76eb728b6fb GIT binary patch literal 103992 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 literal 0 HcmV?d00001 diff --git a/classes/fonts/COMIC.TTF b/classes/fonts/COMIC.TTF new file mode 100644 index 0000000000000000000000000000000000000000..840f27f44ff6f86e66310d770721d4df887e285b GIT binary patch literal 63040 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 XYUgmQF+wcm*@1)aVoGDNcFg`S7tEP> literal 0 HcmV?d00001 diff --git a/classes/fonts/IMPACT.TTF b/classes/fonts/IMPACT.TTF new file mode 100644 index 0000000000000000000000000000000000000000..529135e63c216b8c57af15c8083f53238e032427 GIT binary patch literal 126056 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 bT$1lcmF7DSU-0L(UC>d&1M!61yte-hIrBhl literal 0 HcmV?d00001 diff --git a/classes/fonts/MISTRAL.TTF b/classes/fonts/MISTRAL.TTF new file mode 100644 index 0000000000000000000000000000000000000000..a0e265b2d4d7f3b759a934e7d7f94c145dd616b6 GIT binary patch literal 102060 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Ξ>rCVMp2upi*&kSF; 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 literal 0 HcmV?d00001 diff --git a/classes/fonts/TREBUCBD.TTF b/classes/fonts/TREBUCBD.TTF new file mode 100644 index 0000000000000000000000000000000000000000..ea49703280dc3076dc1413f0f38f97ce2e4e7556 GIT binary patch literal 56576 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 z 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⋁e2>fNc65pP;bPsC0cm&#odr;$U*juO3ANDSSsZi3F6pTTCa7%D^P`VB7 zg}20b!4wO`1d}HKOCED9iWQy3=JC3r4z-X^b+5&2Ny=IlTEpF&q3Qz#DkXD+o-gY$ z`g@#4i<5>>nh#;@WZMK-7tkgGq<(|T0>;zmRsf5_G(c414k_G zeW;O?=YO)kY z@@&_VX<~}SnB_2~TS3ymto5^g|DAg$p7)y#Iv`$;8UEBI_pdoe%$BgMzupXZ>$wk3 zd~(foz`UMtW7`u;FT0_g`m{};$Pz{oH@7*zpvyVK+2>s2lsW;bzeriFV14WIyRyKx zmK3Yq>2O0b_obEh0dLH4p6USWLoAa2EnQ0T8LT+HZcxB6Kmj)F!(%2iY$0Mf>Y&YJ z>hiGW&}3R9l)&_cl*e0K{2w((nR&h6PL4BwEM`k?GFKPw?4Ma!$bauS{xk;hwfs&X zxv#>MFp+l>CW8P(5D_Rc!u7yMpaswS)YxePt4eJMzkOSOr?{#RgtIEdfL;?e_~hfF zJ3lOgd6)rHiQIsF_htqH40vHI1_bQbnM;bc*guCH#0Y))(MK7KJ3%KL#|*3u^BPJG z(-<-5!>T~|xUgaSufKIGR`WmCjr;0ny!G6l>k?}*8`kV;(PNKiv*A_TpQI`g0|t0@ zZa&v4@tsf)CiPm_!C>Zwsa81RqF-s(TEKoJFStzhg`$3;(-yWR7kUE=Q*o~DQ2*Pf zUWHRJd>o=_{+wBdXbE!+Tl-qiMr-zep~9tFJD#D{_2oZnb^Z9C9|=1L6}<}g4t}R` ziG1TctotcS`Nc50zY?xk9~I9*5B1D(2yD1#_+{`iUgRFc^EcS@XN~myS^jo5j?D)y z(mLj^i}ph1=FiUfbN)_0;Ulc}>s29Puj;ThGo7v7Ort>7CHnF* zk13>>mSBqzIuBU)(wwv(3aOC!L9jtQnJRg1MT^w^oA3Ni<_8Q8!1%xa^S6zvZ?KXB zhJjC%viJv3V<*!;Q+43R!Us9iKO==UsK3d2(r1IN3=6rJ>7S_~f6Lun3h6>fi;HQ# zkyZ^uL1ZBtF?lq=@B1fONHKo1i5jWplas=-xDRvhA>ewtzD|bJJX_ce;hO)p z!Y_aS6%gOsd3lphyd?hR={vW4$)^kZepUE=3Bmb>`}o{x{y{;$^V1+t}L>qdn@g8HUM~GUi2El^4^fw8t`C$c3NxVXH zXePjVk$E6&1BQ&MR611blTom6|RBy_g zL~I>Xul0d=o%k*bb%2FBpoOaQjP^|SuuxbsFBaE8m-~IJiFW5Nd&SECQsVE|{RD0h zUcrb%Sj#hPA{4ct9-@KJ&R`hFTY&F~2{(M+2xRO?HjrIVPFe$*ym7S%qh3X%=Y62T zYSU)SN|rE?Bj+z+cmYWP$KRkw`@(cq6QuQ%uVa{o<3i6+!x$CWH#8xGrq|(d180FM zRv0t;irGD*=0s{n*URGm_PZZn{=k&B>JhwX5Z$Oy?WQSfN2{^@UU|NKMN~m z8t*X(V=f9M{knE+@IVOwNe$`5Nw7KeUU<8AH2KaM-OHOHuWK*ei63fxc;ODXd1=#b z(1SvMSbRyh9WxFSW(;W{@j=2Mhz7~TZxy7iaA>ZBzBqPqU~dA1d7}WVF*66BhHR^# z9peoKOe+0mi zU!L2)yZ?K_BH}z||G;zwF9dt*x$VDWx{rb(*~J@tq|50}8?EU0HC;|7dt^Gtm=2<9 zwsXTUNQxQa5Gkg4@x1M&gk+= z9-F}&@+7wSzZ2eK7=kpo+6<2(S+|_p;`mOC)5o@mXz$0{?VsTS=E5LO-$*k-U5KzL zW-0@LOvaEQx4*ee&WDM%28m(tvGIYFI_W*oe?aZ@%fCdS6alpu1Op$Ui2>ksvFg#hkppj zfH&%djU>xvNkRBCBq=Dwpd+v&F{FuxqRW9oI-$O>-1}b#y?m?SJGK6X@2~$1>nY4t zrLWP}$=}c;`Ae~zL_6etim18Iw=l^caQpoME|5@o68RMY|%r9+=L z{G=mpem7QKW}8lS*+s?ZhYGXR2q&0F0M;*KLJxy^hoYM;%Cij$--}UFoiV{boZy}f z)n@ERc@)=dyLmPi`kIO}%`i`~PMA5fVg4f_#-Qc~O0cOVll|~a#hJip*{SM0i);Ob z?Y*ZQ4YS8`Yk$LVYr0xF@%V-4qiMY*#@r!0D z%=Bmo_wn;I7j9x%X}y3x{?G8+2KfMb6J;j#`BMsyiK}s+<`g#DP)f56-)P@tpE}zx za6ursdRV{hfF!62i=uJdRPLetDuRQfrIMrq8v(*7m+#E?<`?B9GN7a0N@|U%`g&4p zTUXnRw!Surej^l((gr4J{hHXZ9G+52?J;~9jyM}bY0L5^c zlwh)n{@V3#f8qb_FW9#^skhuwj=le&w8{cdfc$?je==5TR_nl;PPJ1a%O{AlFmjyW7ONq7lhOrkiUB*Ne_By){HLO{deW z71TJ%{z{E=JJ+er08G&?I3=YSfKtW`ptL!I`o^HO)L3q5DHm4c!m12dOPzzE{lD3| zwwmR4Tk(7?B(FzEJ$gVb7YHfVFdC>KPZUQD4XFb}=a7(9Y{sI7++O%n%P$YR3EoWk zH2?>GaE?Q{2oA}`*kZ60w}f063_>YxbKd(c13z2bAkD^<4+rkQnZ{TQ_(R_GsU~5xf@jFqEZ?mv^{~~&LY6E}m?_v` zNXm^G@&xyrGeUa55t2%%h8$bsHO=ZIpoT;bbpxnol&UeOU6>!Ymp{m3BFFRHs{0#} ztg+V!;%0`NdjM_(fOZNLv@Sp;^)crdyCuDkEYQgolAi*HIe^@y5r~b^--M%L3yvlR zK6QhNIi=!E@qC4JSo~NYLSNUKkC$|ICMl24_>&ppRaFFc6SERtT9jJn;B_l?M>?Src+9hhRkE*v`y*gqF6Q*`naO5@bq zq%5IM+2O1fdB}T@bypW8(Gko~&;7uO>~JcIBi=s7T(6 zR2{nWFoSj-Ak8l5I#9H*qa?j;j4?SN?e|9my7NeLf#>f*_|bY9E2?N--hycycoujF z7WP{IJIKk&W5@dY*a57es(&Ujs#Ys+`_k^V>Uy# zAES@`NpXWoRS)~;;Yavm{n=;NH*|F9_K&M?7&oq=p#x08zkoWqT3>;;X&-C~Nmzk; z8yDQym@woH=ag$i+CuFFuG=CF@XJUrucXo0r>QF&1?x3N0Iy{AeQ+^a+B|}Yk-e?oPT|5GtsIt5Q>hXGMnHerR^veu3VBA7?8Hv66DmHRa0~sc% z$gzQ#uQAS8HQCcU>p-DxUVixSH8aL9xr(T89cpEQ4!T#6O4j9l5iCst&wz`-LY<0m65dY# z2}~I4D3WG3`EpWCVb>*peQ4()eX#HdKlSOS@g5wpFfThr0y9n1v0V zMYi%laU`e8IvW)9)OF{nIwCl<(pa~nS+TLD08r#0b~rpsRk_9V0>0~;#GJ=KLPM9K z>B-A}dC{$pEQTMX(|4`EOEioXF7N+i>!y7F{riRI+EBu=Kv_E<^LaP<9a!t;*8;Nw z>s^D(?zW-(=(f4tHk;dGHW&d@0mye!foNr5-RQd9q@Oz2NDK}`w+|cN9=i)}30w~G z0D4ow=`aJJ7^4Qv=dnW%2?6QXp(JFRbMhqeuGuUwk6NXPDqG*eR>cGCUJ}F+dfRB; z(42D#qc7WXZ&T}-Ni;jJymSB6z$bjKW5vXOu$lJO{~mYx^>NE53s=%81)mv`({MJ% zi54)VfqS?39$(FowWE^8m|0OVU=?eEzSp1hL4-UHA@$t55GhbN2ZgJw9I)-30vY$+ zEXI*)jNCXaM%b8QilIoQ83_daQjo<8(Jl+>H=0!ZMH6wjc_|1++u7J&2M;GVlNVrkidOo)lj1uQ}a9S4bh^ zNSXX8+Ms##W&Yu;uhrM(6FG8LC5RbVL@e^G_DJw$4bWP^O0~j4I~>gjVSC8I0Sg&u zhjPej_Ks5l#z^045%U>y8-o|KaQf&$D3B6{LLWRzNkes#`y2-TcE^t$PoeT5{#85A z)s8nEIv}p{q0J?$JkA^mb5raVOTgh8Zw`>lPC$)9IfzDA&G{m!{`9NDkE7_(NR|iP za$Hq07!=g-bdX>0yNYW~0RdFu(!4U3m1(*v1I`%@;#-RcTr+MhJh$!#VPSIk{oVl| zjl;XddBS-Eej0`6?z^wQU-Q&xFMvS=ZY1`jD=?Y`xpMepx&43*SU36wdI9^aydPV! zYsvwp3`iDXbr|@=z=dq}clib0Lt307%;B)iI1uIiQ3w<>*t6D4Rvxphc#spvNd{xQ z+c1D}t?vIAt?5wrW`_AAs+*glGZo1)dGI2D^efF6hC&U8F}zKu5;n!4@8^ zP>6RxEvD-R`4P1}RWyFM@gyvVn0hi>Ak!`p5l__(AbR7E&!q_>FbAwvC)0%0v|!V) zyJb>wC~^q=C;P(RK3aa(zNRN8E+{-#c>m|G^4+{WacN@sp~T zy6XHHoflnQxc`pAQ-w?4egPmN*F|SsGPB=UH+gs*aQC*yzb+c=Espgav?`RTktFeZc=2OgndR$t;;uhIymo z%mE2O{K|N^{IOaE**hMNFrcQ+c<@-`DM()GPBCv$q*p|Pxh8!fGec(eioF@k$w)s! z@&Mm^h>xho+{?W1a@nNrKk$bBhZctyUwF~}BZc2hCKF=aPoI&0d$|9gnCjmX`{hq~ zEBHyp%tJp+lHetI^5U2A@EHql@bFx(j)ylNfwPBLVY*cvwY5MRLIDhdk95+)-fnZm z)noJb7~#Q2#;`NEIil(TLdlCzBnQgC7Nl$=WEN2HR5(}$stg64D0HM4WI36EO?!r) z@Y16CJrnsIL&5I~e^{;^@gmZ=Gb%)UxPR&;n=Fl5)3jUuSK(YJS^fqZ*LUSt|WfAMxED;aop|*PXNHtQ$RH-Xk|WR(N+6%6L>5FFH}iGVam*HR>z{8~L5S zUf&|$YTss@VCZb%R{+QK zA3xdz*lY%=!zMOfb?Xg^x#|`i%C9PxkQNSRk4GnE=1pIGv)QSie9;xtYttQ@7G1Hh z>zW_#zed=#uw~Y{*DRbl>4NGD#xIyUbxW}3`YZO+4B_;bQrIL@5YV||Mj$~!#b!qj zrZswKlXcr|P?@$td3uc<`pawVLJt0(C9d0p-e3*+KhU&Q;R}y*TOEq2$1TWiivq<@ zk*R(%KBFO(O(z+qGQ?D1GR!R1?xCczddBDq=3`8lW4#5Nro)_+@Zv~W?EOj4@cL)I zZFz3RHrM5AiujQKfBcr`LUbN z1v&%00Z{;=GDb|*Lz(E1VO?W0hoMBz`6Jng5DA#a8Qr{FH*Pf`{R1&G^T7!S0C2D% z*t=|9vd|Uj;tb<`@MUkrq(>Y5FaToqgf4*kaX2FY=nvsQFu?gnv@d)`>!L0(rOQES z3%xnaJDfg4Dp!_PH{AgrU?`K06@<`xKQBCfvhc~`-eAER!cq@M^f6D~kcQZeq|8xJJ3dO?AE2y`B52Mx<7`13ozA%4QD;(y` zz!LI=US~A>%~`Vuv^0aULlWVn7uv^~hpIQRI5X)_ur4o)p$qPeBsjg%X^RBZCN@_v zzeYO(RPZcv#lkQysM=;FNt@jORsN7y_-f~8-op3$|3|oQoo?h;FRYX1o$ds$vt2ia z45IG3ZTl~6#_GbD3p``maH~T7UCA92pJ#R&KhNI+$0d?Ql;Ag1uQS7ms1c~GaJP|# za6{nWCdv#?jZk&m3=b81jH<%p7e<3v5=^XypFL|y@u(9}b+p+7$MH0G${9N~Xa{UV zstb=UK<1Ii22KTtPOauH4dUL2nY0;$o}@Dn5OiG~HcM%#ia%5=)44$PFFksg9)Sm- z@Jw!6&GaAxg)A6016s&lASJ>7AwssWwBIRW z?#Hl_s;bJ$5D57*Aq;R=5eAcV-oU+61Vj@HQ(c`*s$sTaO}L-QBhxI*wt+IZd`Qvf zb-A<@nb#H89?oWE*!HE`9^4ep?{mAga1>+Fa4k|*V|@32jj^At3Dp?ieNBr|#oke4 z#9%?5O-^Gr=;e~!wtUZO_zX2h{E@!MnuxTf47xbL>F_umK7&s0g^wvt@AY;=>mRdb zOq29FFPDk}Es~r$@*c_K^f?rRF4UvMf%&2{D+VuH6_8^RQb=lihxY6l=V2Hi>B6fe z5O=lzSLeH`PN!xbGsGuJ4*N(sv4!^2n3haSPWo|dY4EaNJ?&dgzDcI?((b9%gX{f&_B zoCOwy6bCZc4vYk(lQAlfen?fv$iOjGCv#%6nm@p!DR+>65fvF=Gdfr>KQ|hCz$hQn z(D)Y$8rf`*H#hh4wNgh%OPwz`F1%>@1$)3vrQIz(_X2T$@ek;=pJ&`(&N$~ShVcd| zfdJIBGj<~gsqA9L{SY-0_oKN`I2F+>u1XUy4*a2TqqI|Z6!je7p3JW!Y1SHSY;X4Q zi}7!TeNc#$)-Zv#4z~idhWZhxfjSMQfEkXw{YJmvpY_wya)!UpzsA4CZ{qzntJPxY zkVEDUOHgpj^xGQ0_%DKT0T_|^t+LTW#QO`*WMfJ|J%cV5YKPs6Kj-9FB;obI5`sn z-F?Z+F1%yauL{4=9sR1Qcl4yRaGkKMe>-@88fbDh^v}xBBOJ_MeZ;}QF4st6XH{>N z(3PH%7Fy*Q@I(k`KY@Fr`n~GUtHlM*l}@ay{a7UhHv?H#&_}TkFC7N6*Su{F1CnbY6WO0G@`sn zg=gHPuAq+}$4CMR96e-2p&dSWG1SDFSUL}A(#L(OuPv2AC0%*|{zzw&uydx%SohST zA3Vz3Z1GDs8OM1*ue0t7-Ts4*pPBb?f{8)bT@);9>wM}_a<|n>{Un>`p8LfmcnIa~a@{a9w}O|rvjbJlh^ZPhSLs_HP?!1Q^O zlU>bdDtS|v%_-E5b=r*8V@+mb)mY5(T-FR3{cx6u&FnOV#UL;W9S)nb%Vg^^yNzbH z3a1_ls{`~(XudQoVked9O;%M^@vG{(@j>5U-3HqRh!O|o$mDl!z!+I$O7T3R^Y8+o zhQyWe{#jj2YjT#bJN^Vwni2SdDFZgiAS~u;Tp!9zzLLs;Rq|4PBPQJ?GhDH+1|UXu zo~Pv#rX+r&FsS_qP$hm#e0LnCq|k0&1VCgiuJeZdA>iQip~`L_{1Ou=`)Wm})TP|s z?vffMbj)kX@tKf_8bUqcup#BnKzF1%&||13;Bp3A&R7zZQN1VGfpgDz5;6+ahteVV zNU+eX3Pc7PdwkXLkksQ1mRsnJYcX?gb653$i(=*!yK<4TMA2fV zygtWTDDsMV*xOuR{|$Iw#qXs3PudnDq|Y^48JHB>3b&Km+=QVVvN?>3a=7ghZN@<; zhvDGB97c_iYDA6k-I7K&VJBiDVL2nlg{(%@7~gFh5@RSd5Tm+7JP|Rfd&|G){)Rjf zz9vvZX(t*}l>j^7mW;H56(bM-ovOcoyEKjGB=X$TOBBy!)_#~P1=E0Vj9@SavHqNfq6x)GFr_R`cSkCfDb64OpzN5y-b|5n8fgOnN_kTkE ztC2^{(upg%G5>go=)^hd9eKwFc%kAP4uMn>xLNho+V=H-Liqc5qgQ>SxDRi5@^XD5 zpV*LqqE@_|O?tKP%tJQY<6tRp?{dA`oLon9ahAw8q}@tsbA)o+#{mshzz#AgIe67w{b6kWu3}CSaw=*JG&qUwfrSN_Bnztn zMABSejhXmMjrsS3F$2mHp?zTuWR^lx%-1vCQe*x-1j}m7TG$~mt9v}uy3{?MZQN?D z&a}2LbdN_o&gx9vnms*A1 z$^|oBI|{Fy7E{0ZO@}b6|HXy;orPD>!^MzltI4E;V+42um7rOJFFHC04|XF$+MuI< zc!|{kL>v(8P(+3J1kXyr@dN(peR_)T_%lF)jt6*;-lfOv7hLcbeD{_Pyhtx22t8x( z5BwzQf%T6ZQF_=hKoDT<8(2yby@z=8@Lx)AApnaP-*B8!3WQ`4P(l&}0$9rFp-KyU zJs1$PA90~9v3FVGlyMdjqD5KMKr9iugTo^o2bb!240|)gN%594%~GL@(ZGsi!0x_Y zXM(R^5RyuOQwvTJB4@}0+^Mik!K4|*qa@*v8IOqe1IHlU5QX*wkmgtzcvZzgkJ&E< z$g5bU@fZ>ysK}a7A?z7ZN|KNr1i)K(O7W7*a=d*8-4LG^CB3|^tm-C<-N@*mz5h2*G>V@4%EFCHr@s0__Q|Sh9`hnp1 z0q+6f4@k8XH)V!62M_c{&>b(S2TPmLO?$uygv=ONIOukkLLxy#0HGgc0^~u`P#iE= z%o120&ln|$dx&^&X@jRK-6$xey@Q8J8Z}Iu?34%g(6wa!sG2t2f%@gTy4j$}A2lGo13*|zs!&#BZfC3_Z3&NFx6Rki+odI;C z$CMf397+yB4Mw6p9SF#%O}&hE&?Bk`&<)=#U}){2syA7X21SnFz-e$1XoYB(o>2q9 zrx6_kyfCvOQGJ*wd!Sn>5`2P&ECG51Qd$5tg%VKStuP)TZy;*Jr8r6%h2jgCg>r?S z!iZLa>j2&KupeY}L(Z@|{C9M-AR{Of=!SRz-$pk$t;n86H=-koPIRNE#4<*bQKP(Q zY4kdZ!w!`hP(BK#9va<@X1Mn?7*G@(_=V~Ubh9E2m9C&0qLE8?0cB8i?6cQYZ8&n}4FuGAYrsPlxylYlt zC5jNWbu4@AnMx$YY@skVEg-&9;mkHf#v%uUgGgq@hDJ%x7$wlIiLH$?D-zL-vWJ6u z|I$IEp^By?sb;KJDgk9uHiI$IW#bOF6hfmL@fb>sJG3wKIMnNy(AJPSsxHnBoi#=` zBRuH+Te{(GR0H+M;4%OPf&meu41#E6M#?6QZZVWudA)gKlVH z2#ViPfuNfW%GcC{kaxvmM6X8MH`KQhS&&f{Zh&rRUqn_SE~6t6*MP-`iRgxS%~m!$ zLS(Ek>V@6Fi6|A_gmop}v{^tm7C)4(iEao9qEhVOHr9;v(oPHs0vlW}W)J7;cYa3{~xY5&78c0B4{6akj(F_1W z^jvF1$T4M7JCJAO+X6?NL^2eG#fT(`DXa>*Ns0%>kwFxz(~iyz*<^w6X~B?SFxim= zm<)&2ii~2KK(S~CIxf7;Dvs!eEjUIU6x9K`nJ_W1AiIc)ni4>ba8TQ%SAcLtdB#|X ztBFcZ`*9_e@9b%HLHVAhqerTYTg5#c8P;W5n z?cfP&Y8I1>%u+RhkIYt^MmOR<^B~=bH5fx8hq6pz?2NmKJ*lotHap7%>$A{8tu_}R zBw5B7CD2=;Z#S47tVl#R8?r}qqja=`S`#r6kpZLx-7G+Jq`W&}hJp@-*b284M=7Iv zGh(0zHtdYjID#u$9Ew6U$hmQFHn$TF z92qT%u+&=--JDb;IE2&diEcQ~pc`5k3P@=Y-RyQdm4N8xl0hCLI8>z@;;_nUI7T;8 z-L-+CF^=E_4ROba&v`r+z}L|%+y)zEa0#7*2fH!aZScYgy2+rM1=<==>;;*vP8ygD zEI95_AAqm37(h2P6?8^sv>jyF$Y^GhWi?h5RxO`;OHGO%nUNz!A=)}wKs>fsZHPd2 zB1_cQ<2MCFkv%S>LKUM@0^={nM5D#UibQlnLg>KcA@yQGYeFKlmBe~bhr?k-6;V;$ zGW`fjQ~r&NOe_;%2>c;Un+5$6$ch*chm2Aa51Jt90o~B+fg=DuitdEY!Gqlx9iSUt zP(U}E#UU$J#0^~+7kI7|9E}l87eq7=H5uJlJEm$v?OOpXsK$zbRzNPZ*?{^48KKPB ztadwvaVgqk@D}ly3u#cFg<_*;vngJ;(T@7Ux`8NxULNj4jaE0Zh{lNnjZgvIXttpp z7Cl-RRWw3SPvCR{pqJRlXoNl{eq?mREybZ_RHYlyNkKi?ATZ}y2<~Z zZcZ8OLP*7WWEC!uZSd@2Q)DP_+cdi2o{DCGx`m6F6P*AkjG__UPzvDQYUBVjs&u15 zfHXMh5sGEAvoLN@g*~UbGFt}dhWF94$#$Q|=om^j&~>^SA$;0_19NpG zB2!vKHSQgAdzu#5q-d!i$`&U!b9Bfr>q40^NwshMrBa`#mNn`ZTP!h!W`K?HGk^ zURETEm*|FLNc^Ax^-Kz~OWlpd4Rw7~5#`-yrym*JC@O?eSSCP4{Hb(9M4f#{%N9tWecEeaI5^ zS$0`=8yya3$ZvMb^bBp5J{?Z*kQ{Kxc$wlwLTHFinx&NvbX*{sgVLg&!0Yu=38<(6 zIAE|@KxuSBhzfBykO?F$V^%NY6^G)K?dWk32t7MWj!syyS-D6=;b<6EWQQBGBMU1r zC7>R703vvuc88O;KaGgV>vG%OEdGGqLDMD*2|6NayUC)M{8Zb>om~b6Wkjer;l;+~ zcBwHUpxus|rcq5hz>rkWc8>?SQUbt!MucdzcB*<;0Mi}N79~)?X-;<}Xz@_RAaXpy zIO3)eBj`j$+KFy%H!|vS(QKo1U`=b6K`I9#1SW#pT145x?RbJlKsj;C8xzbm{e& zkhtINb$DHh%i{`B2Ww%$ksgwEnyq$o2t0v?WJ5^mu#lYF?IPcTYOD%7TQqLE0JMc2qhu3TO zdORL2eu~SE28cx9>em6!in1IG2Av)k$N^AhFa3zpApeL8ak#yd35VT`Kk$d!;dQud z=nrwa>>j5F*>x%~sw#63-7F5f`+uXG%k6eLyj~OPDd6!sy&$~D6?VF4@T6oAnbYO~ z-5eI8CJiJ`djLgK>E?EN2IxjV6W!=jJyg26oqj*jHZn*zHyFwbKOJY#t!$8PAf?sn zVRVbS!6;6ZZm8fh=;pv&8q9{u2j#$np-_lQKy-_F9VV#4D(*qL`4A7nS@7o|I(eNg z*(KX;xTJtJSY1wU5K|w7z&UuZ8#&_hczteHz;8x9g@O7IfboOh8}|T0 z#>Rqs93D4V&?396F}K@;hJ-Z2$R{Fn`FvitKj2qm1^2mO>BV|yd_xI64i~uD<%I_w zAHu`~6cACn++GkS5JPX~V*Kq2S$w`gs!R^KkWEC6FtY4N*Cx9XJ~wpGs6GM#WYq7s zsL8P_8X$<~b9>w##OR1dqd-IiIb=B*aG9M78j!<-TOU-qeL=*77GlMp%kTEP17K+M zhl&R!@_YR7Pz@G>6_kfV=OTOEfha~Rgupp?up1>F^ap}IZ#ZOi`#tec*cV2Gp+LFM zPeTKRMtVMn$7fSKwj|&md}t9qPYi`egx+8<;0uLAYODz8^U;V&pX%YlFD`Gu7mZSw z@-PL&FJ4~&YJ1@%((s~W0k1b^3&L+#N{OLkSHM)zOa%9Y(Q|s!K@`{r4zh;Bo-jDd zMzN@e2My5Y_6Ct%QUr7*5(!@z%?5eThUrI8+U3J-(2Kta;_>-BHvD-)zK}2M^Ft}g z?ZB1YQw6!W+FBonPG0eQ!*K)Z0$qm#wN*OUjUx#+W8r{57PTSqWCR$NA#W%e%77pa zI}0B41OrZAPY7mq(2C@YKL zTQ)`k5w$-M_Io_BOn@@s^auU^gd7gXYAYNGKe7oT;1Sw&46WN=84iR4a5ieQ#bUk~ zI7+5i)WauxT>&o=2nK?P(UVH0f-z7LMXieYY+e^A?Fr&G?8jdm@dN@s1%JLsAQFfL zLava@i!CX)^|Il6}IL2on|E{nz@(J)xBy1F`A9t%-Xn^GaP z&Uhdmh~l;^jK37(i9|vU{Dl(HM6^5-^TyDC!N#FvG#MqH^K-+8M>urqu4p(}VFC|F z=^Q-Rji)AAmMo7&Gif{OsXCR3qkxHYq9I;}p@9WQ#l(D(xYHAH)yHG;xZmfGhpQry zFd~ei6tPq$t;QOP;XqA09kW#j;;|$*cT5+%aPr96f9U* zR~OGDBUIE}CSni!lA&ZMj$0y2dA6ML6>;G&l8UF|nOMS~@P~c4M$++goOmwCjUAid zXnah@vvn4<>m;3n2fGOjt4L=n%9AzKE>Ntgs;0aKq^rubrP3+%LKHd`OO=NbDNi8b zX-$=fX`6lQo01;pcI zDw~YPYTC*v6CnT)B^%ro6*Xhq0}V-JGg(%arq8OH7;Z*Zlvk8P5ys`JsY%pSRaJQ? z7WGKDSYr$GH^E|*KyWXhJ%AGSI&C&RnDX(e9P=pXT2M=}=9$s5nQ=82+HF(Oa(rxuk6;0LU z)eY78%Bl(wh(cE;E3?sbr7xWJkE+O4R>q?7%2aDQRgMTVwY4?b`lbdo)?^k3jaU`* z1wkt-6PZjlk*TR@Zmvg|F-fKQUxWrb9*W|bWWk_ zY~u(U>Y|#?!GqmI^G$V)P1V({Exv4h<>=`UZC$Mvyf$51Q&w3Uh*pNi z)zsA1CKJipicu&#BCKv|YOHQ>24a2M=`LC~hA%KG|-%KBX6S!WGLm?@(uARgB@+mX%q8;5vcdm6`IQ$Cl^jcplTIlQtyi)-VU)-kQQx?Eii zRJowhg){e^dTEZ*{y7(dQW=hipPXu@&wUR>ti>t)pBSqQyP#)nW#Q=uykpo{fLf{H z)8dq(4XD09g)QWegKw5NZUa3KKEZi0``jdak9%Hfw@* z{Z#m*_z&c{Txu+SiO+vX!?;n>N-iYs<7VQsN1Dj>i7mzBl2rT~?z>@eeS`3EaiwJ9 z77II(=O1!;X%5#dox_cnRu=yUVJ3^yxf$X}&Lm#Q9h6pZbH%@M^K_qa%O#=ssrV@u zgLQxr=_irit4M!6%D;h?o61h*MwzuTUCr`OdHNS8%Omnfc`ThQf0Re<9LO8xZ|I49 zQQk_Y_z-tF^7B*VX&-i_c zVGz0fC4;=iFM<$>{@#BE^T!EaP&bW$B4KNUC^;q>CX2ekV(K3~9@!g(Fe zi*WXVmz#tOxv|8z#5=^J#3%UebF_mv=s1$)|9q~I@fqkW-pNl8@8tf9^Qe9k_Zyst zaBe2L6K$n^#rIgb8@Ve{uARiUpb2l-qP8dEY1W=fX@d8}zk}~fpTz%Y7kG#Ihog)R z#D_$WVQ9;L;l}E=fd46fL?7bA(kI#`%5xL7Q8@b8M4vcsBEBY`9QdSmOMFRfHq6Z^ zeGbq8ZCI@4_EB3FzvK?G_5i*ueGbq`qZeqg3f&ocK7lNxzr}9=zR@oMmr!2Zk86AJ zE!dxk_+HNCiiA1RR+MlZUTnd&y=cPq{Nnkz&MYp*^}^y~xE?4JV81Ei-3m@AEWy>m zuH}fKjyxyo@-cBRyFKx@AX*AAqWpQ##&%Z5c9d~Ho=4fWyzn)?cOd`mNIiq=#NzX~_7v-JJ-2uPuG5N9TxTFZ z?Wnt5@RM)=F;7R#f5X)dT1`jH^!-5bbMAajL5a>s-t=%4rWC!nI&i%Z-yOI*aD9?{ z5;;GB9PYsNyy9|Pdr`9o5W@%>Ex{A&-*vE1y+N2LyezI09}qv3qS8;Kk8~kjtL`G* z7Tvr0jQ)t>TZT7`-NvIPhv|3bh33bhAl_z~Yq`TZ*7_IQBsnC17xKExm1phE_M7a_ zLU_K-aoBl>E9$xmDB}-%(wZSE(ZAIHUZ5&4KCm<-^Q;klgh44h>3d=r;{6#pO>#He>L@5I-I^P{d}e=)0KHD z^LbXzrn0&0#O&Pc+U$3;d$K>v{wn)H_Uj5qMWUjmVnW62id7XiR@`0jlZsa>{#fz% zO7s71>sp|jsM7F%OPZ!yELN!^lnw|ADJ=~xElq6NJf^fwCQW7nwBUm@oi>3qlbs~> zKm~lP>{&rsUpy4SC%(|O3OnxYe<#)-hUe~3rEw0_Jr`-m3l{@ZU?;dau^RxH> zzmC6$f3GRf^iI|G)`%KvqR}NphjfR z+JG_xJ+7Yz1QsX?-8O)uWkuFT6e`jCZeM=Zu=awa)dPReSZ+*J`&<<4|CBBwY(YDtA+(eUxY$J6wbHJ;Jv`t!;e8=2(-A>&Lpqao&osCYJ4c3G*pqk6k(79-+1<1H6s>ZrmgSBk|y2?s6tOoTM0S(lMZg8S| z-55blK&Cb023j$Oym+KOYQtyGoiT>@J5%jnOD6S|)M z0v4dZf=zV;ZKNx~ufK`@Mpx4{bS+&+*VAT%652}J=mw0r?Q|3Epq+Fxm>+MY+vs+> zgLcuKKqK8v_t3qxo9@HNAD}@Rq6g?f+CzJ>ay<-=p-1U4dK~;ZPtcRJkDj8Z=@}sJ zpQY#Mc~A(wK!2zG^bfohy-36K61_~X(5v(sy-sh?oAghx2){*d(>uUO9-w#WAiW3N z+6VL@eMBGAC-fYL_gC}8U-sZ2pE9>JONR$3)pxB4lHDdRLF|hDeP1>krji+?R18?ooq6jf*>DL z5x$FK)7W&xd7Qy!0EC?jVxGb>|rSUIa;b6F*`uz5htSLeFrSSmEGH*Fc$7U|7T zcBdk%5)nCW>QYiMIhkBx=&r1+%~$#`5rh?0E(|NZy`fMzEXPw3%u2@IXcw{?9i6J& zCmTZKjO6jzOma38ucyko@`l3clx&RY%B!D@ zWt72-D;i?jWqo>bTvt9lS3INg+qydS()r3U%P8s@Rb7dCepOeJelnR+reIj^ipF9g zQz~m1gL<}9M&&M2qw${Hw06v2bgcgT^fAl0RIhDyMj4iBEnba7LAR1tlj(%4MimvK zym8mEW=rW(hy)QK0Z0qP4_PBxN~3N|X**;IWHH1CX@dxmCI}DtdhO`ioK5{Z`v>~> z^&2*&ccur@`_eC^bCM=GaEAb3Ymf8n5mvndrYhX~xP%$|>$`~J&oXq2IA2Q*m>s(zIPe|B@YHRr@ gH%P(u!N%ns?x9LbJU9>2)uhDfi6pi^Tn2ac3)d%P@&Et; literal 0 HcmV?d00001 diff --git a/classes/fonts/VERDANA.TTF b/classes/fonts/VERDANA.TTF new file mode 100644 index 0000000000000000000000000000000000000000..f5ae77314f41dcef9b5450e0aaa68f7dfe1bd1a6 GIT binary patch literal 52720 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 UdK|*>(B>_hH*YD&Kf1gB5A8N5iU0rr literal 0 HcmV?d00001 diff --git a/classes/fonts/VERDANAB.TTF b/classes/fonts/VERDANAB.TTF new file mode 100644 index 0000000000000000000000000000000000000000..5a733639baeb34cb3c275dc24724af3ddbe9f787 GIT binary patch literal 53816 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 Ho*wWI98@5& literal 0 HcmV?d00001 diff --git a/classes/permissions_form.php b/classes/permissions_form.php new file mode 100644 index 00000000..757a83f9 --- /dev/null +++ b/classes/permissions_form.php @@ -0,0 +1,262 @@ + 'Can leech (Does this work?).', + 'site_upload' => 'Upload torrent access.', + 'site_vote' => 'Request vote access.', + 'site_submit_requests' => 'Request create access.', + 'site_see_old_requests' => 'View old requests.', + 'site_advanced_search' => 'Advanced search access.', + 'site_top10' => 'Top 10 access.', + 'site_advanced_top10' => 'Advanced Top 10 access.', + 'site_torrents_notify' => 'Notifications access.', + 'site_collages_create' => 'Collage create access.', + 'site_collages_manage' => 'Collage manage access.', + 'site_collages_delete' => 'Collage delete access.', + 'site_collages_subscribe' => 'Collage subscription access.', + 'site_collages_personal' => 'Can have a personal collage.', + 'site_collages_renamepersonal' => 'Can rename own personal collages.', + 'site_make_bookmarks' => 'Bookmarks access.', + 'site_edit_wiki' => 'Wiki edit access.', + 'site_can_invite_always' => 'Can invite past user limit.', + 'site_send_unlimited_invites' => 'Unlimited invites.', + 'site_moderate_requests' => 'Request moderation access.', + 'site_delete_artist' => 'Can delete artists (must be able to delete torrents+requests).', + 'site_moderate_forums' => 'Forum moderation access.', + 'site_admin_forums' => 'Forum administrator access.', + 'site_forums_double_post' => 'Can double post in the forums.', + 'site_view_flow' => 'Can view stats and data pools.', + 'site_view_full_log' => 'Can view old log entries.', + 'site_view_torrent_snatchlist' => 'Can view torrent snatchlists.', + 'site_recommend_own' => 'Can recommend own torrents.', + 'site_manage_recommendations' => 'Recommendations management access.', + 'site_delete_tag' => 'Can delete tags.', + 'site_disable_ip_history' => 'Disable IP history.', + 'zip_downloader' => 'Download multiple torrents at once.', + 'site_debug' => 'Developer access.', + 'site_proxy_images' => 'Image proxy & Anti-Canary.', + 'site_search_many' => 'Can go past low limit of search results.', + + 'users_edit_usernames' => 'Can edit usernames.', + 'users_edit_ratio' => 'Can edit anyone\'s upload/download amounts.', + 'users_edit_own_ratio' => 'Can edit own upload/download amounts.', + 'users_edit_titles' => 'Can edit titles.', + 'users_edit_avatars' => 'Can edit avatars.', + 'users_edit_invites' => 'Can edit invite numbers and cancel sent invites.', + 'users_edit_watch_hours' => 'Can edit contrib watch hours.', + 'users_edit_reset_keys' => 'Can reset passkey/authkey.', + 'users_edit_profiles' => 'Can edit anyone\'s profile.', + 'users_view_friends' => 'Can view anyone\'s friends.', + 'users_reset_own_keys' => 'Can reset own passkey/authkey.', + 'users_edit_password' => 'Can change passwords.', + 'users_promote_below' => 'Can promote users to below current level.', + 'users_promote_to' => 'Can promote users up to current level.', + 'users_give_donor' => 'Can give donor access.', + 'users_warn' => 'Can warn users.', + 'users_disable_users' => 'Can disable users.', + 'users_disable_posts' => 'Can disable users\' posting rights.', + 'users_disable_any' => 'Can disable any users\' rights.', + 'users_delete_users' => 'Can delete users.', + 'users_view_invites' => 'Can view who user has invited.', + 'users_view_seedleech' => 'Can view what a user is seeding or leeching.', + 'users_view_uploaded' => 'Can view a user\'s uploads, regardless of privacy level.', + 'users_view_keys' => 'Can view passkeys.', + 'users_view_ips' => 'Can view IP addresses.', + 'users_view_email' => 'Can view email addresses.', + 'users_override_paranoia' => 'Can override paranoia.', + 'users_logout' => 'Can log users out (old?).', + 'users_make_invisible' => 'Can make users invisible.', + 'users_mod' => 'Basic moderator tools.', + + 'torrents_edit' => 'Can edit any torrent.', + 'torrents_delete' => 'Can delete torrents.', + 'torrents_delete_fast' => 'Can delete more than 3 torrents at a time.', + 'torrents_freeleech' => 'Can make torrents freeleech.', + 'torrents_search_fast' => 'Rapid search (for scripts).', + 'torrents_hide_dnu' => 'Hide the Do Not Upload list by default.', + 'admin_manage_news' => 'Can manage news.', + 'admin_manage_blog' => 'Can manage blog.', + 'admin_manage_polls' => 'Can manage polls.', + 'admin_manage_forums' => 'Can manage forums (add/edit/delete).', + 'admin_manage_fls' => 'Can manage FLS.', + 'admin_reports' => 'Can access reports system.', + 'admin_advanced_user_search' => 'Can access advanced user search.', + 'admin_create_users' => 'Can create users through an administrative form.', + 'admin_donor_log' => 'Can view the donor log.', + 'admin_manage_ipbans' => 'Can manage IP bans.', + 'admin_dnu' => 'Can manage do not upload list.', + 'admin_clear_cache' => 'Can clear cached.', + 'admin_whitelist' => 'Can manage the list of allowed clients.', + 'admin_manage_permissions' => 'Can edit permission classes/user permissions.', + 'admin_schedule' => 'Can run the site schedule.', + 'admin_login_watch' => 'Can manage login watch.', + 'admin_manage_wiki' => 'Can manage wiki access.', + 'admin_update_geoip' => 'Can update geoip data.', + 'site_collages_recover' => 'Can recover \'deleted\' collages.', + 'torrents_add_artist' => 'Can add artists to any group.', + 'edit_unknowns' => 'Can edit unknown release information.', + 'forums_polls_create' => 'Can create polls in the forums.', + 'forums_polls_moderate' => 'Can feature and close polls.', + 'project_team' => 'Is part of the project team.', + 'torrents_edit_vanityhouse' => 'Can mark groups as part of Vanity House.', + 'artist_edit_vanityhouse' => 'Can mark Artists as part of Vanity House.' + + ); + +function permissions_form(){ ?> +

    + diff --git a/classes/regex.php b/classes/regex.php new file mode 100644 index 00000000..55600b58 --- /dev/null +++ b/classes/regex.php @@ -0,0 +1,13 @@ + diff --git a/classes/script_start.php b/classes/script_start.php new file mode 100644 index 00000000..977528cc --- /dev/null +++ b/classes/script_start.php @@ -0,0 +1,2247 @@ +handle_errors(); +$Debug->set_flag('Debug constructed'); + +$DB = new DB_MYSQL; +$Cache = new CACHE; +$Enc = new CRYPT; +$UA = new USER_AGENT; +$SS = new SPHINX_SEARCH; + + +//Begin browser identification + +$Browser = $UA->browser($_SERVER['HTTP_USER_AGENT']); +$OperatingSystem = $UA->operating_system($_SERVER['HTTP_USER_AGENT']); +//$Mobile = $UA->mobile($_SERVER['HTTP_USER_AGENT']); +$Mobile = in_array($_SERVER['HTTP_HOST'], array('m.'.NONSSL_SITE_URL, 'm.'.NONSSL_SITE_URL)); + + +$Debug->set_flag('start user handling'); + +// Get permissions +list($Classes, $ClassLevels) = $Cache->get_value('classes'); +if(!$Classes || !$ClassLevels) { + $DB->query('SELECT ID, Name, Level FROM permissions ORDER BY Level'); + $Classes = $DB->to_array('ID'); + $ClassLevels = $DB->to_array('Level'); + $Cache->cache_value('classes', array($Classes, $ClassLevels), 0); +} +$Debug->set_flag('Loaded permissions'); + +//----------------------------------------------------------------------------------- +///////////////////////////////////////////////////////////////////////////////////// +//-- Load user information ---------------------------------------------------------- +// User info is broken up into many sections +// Heavy - Things that the site never has to look at if the user isn't logged in (as opposed to things like the class, donor status, etc) +// Light - Things that appear in format_user +// Stats - Uploaded and downloaded - can be updated by a script if you want super speed +// Session data - Information about the specific session +// Enabled - if the user's enabled or not +// Permissions + +if (isset($_COOKIE['session'])) { $LoginCookie=$Enc->decrypt($_COOKIE['session']); } +if(isset($LoginCookie)) { + list($SessionID, $LoggedUser['ID'])=explode("|~|",$Enc->decrypt($LoginCookie)); + $LoggedUser['ID'] = (int)$LoggedUser['ID']; + + $UserID=$LoggedUser['ID']; //TODO: UserID should not be LoggedUser + + if (!$LoggedUser['ID'] || !$SessionID) { + logout(); + } + + $UserSessions = $Cache->get_value('users_sessions_'.$UserID); + if(!is_array($UserSessions)) { + $DB->query("SELECT + SessionID, + Browser, + OperatingSystem, + IP, + LastUpdate + FROM users_sessions + WHERE UserID='$UserID' + AND Active = 1 + ORDER BY LastUpdate DESC"); + $UserSessions = $DB->to_array('SessionID',MYSQLI_ASSOC); + $Cache->cache_value('users_sessions_'.$UserID, $UserSessions, 0); + } + + if (!array_key_exists($SessionID,$UserSessions)) { + logout(); + } + + // Check if user is enabled + $Enabled = $Cache->get_value('enabled_'.$LoggedUser['ID']); + if($Enabled === false) { + $DB->query("SELECT Enabled FROM users_main WHERE ID='$LoggedUser[ID]'"); + list($Enabled)=$DB->next_record(); + $Cache->cache_value('enabled_'.$LoggedUser['ID'], $Enabled, 0); + } + if ($Enabled==2) { + + logout(); + } + + + + // Up/Down stats + $UserStats = $Cache->get_value('user_stats_'.$LoggedUser['ID']); + if(!is_array($UserStats)) { + $DB->query("SELECT Uploaded AS BytesUploaded, Downloaded AS BytesDownloaded, RequiredRatio FROM users_main WHERE ID='$LoggedUser[ID]'"); + $UserStats = $DB->next_record(MYSQLI_ASSOC); + $Cache->cache_value('user_stats_'.$LoggedUser['ID'], $UserStats, 3600); + } + + // Get info such as username + $LightInfo = user_info($LoggedUser['ID']); + $HeavyInfo = user_heavy_info($LoggedUser['ID']); + + // Get user permissions + $Permissions = get_permissions($LightInfo['PermissionID']); + + // Create LoggedUser array + $LoggedUser = array_merge($HeavyInfo, $LightInfo, $Permissions, $UserStats); + + $LoggedUser['RSS_Auth']=md5($LoggedUser['ID'].RSS_HASH.$LoggedUser['torrent_pass']); + + //$LoggedUser['RatioWatch'] as a bool to disable things for users on Ratio Watch + $LoggedUser['RatioWatch'] = ( + $LoggedUser['RatioWatchEnds'] != '0000-00-00 00:00:00' && + time() < strtotime($LoggedUser['RatioWatchEnds']) && + ($LoggedUser['BytesDownloaded']*$LoggedUser['RequiredRatio'])>$LoggedUser['BytesUploaded'] + ); + if(!isset($LoggedUser['ID'])) { + $Debug->log_var($LightInfo, 'LightInfo'); + $Debug->log_var($HeavyInfo, 'HeavyInfo'); + $Debug->log_var($Permissions, 'Permissions'); + $Debug->log_var($UserStats, 'UserStats'); + } + + //Load in the permissions + $LoggedUser['Permissions'] = get_permissions_for_user($LoggedUser['ID'], $LoggedUser['CustomPermissions']); + + //Change necessary triggers in external components + $Cache->CanClear = check_perms('admin_clear_cache'); + + // Because we <3 our staff + if (check_perms('site_disable_ip_history')) { $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; } + + // Update LastUpdate every 10 minutes + if(strtotime($UserSessions[$SessionID]['LastUpdate'])+600query("UPDATE users_main SET LastAccess='".sqltime()."' WHERE ID='$LoggedUser[ID]'"); + $DB->query("UPDATE users_sessions SET IP='".$_SERVER['REMOTE_ADDR']."', Browser='".$Browser."', OperatingSystem='".$OperatingSystem."', LastUpdate='".sqltime()."' WHERE UserID='$LoggedUser[ID]' AND SessionID='".db_string($SessionID)."'"); + $Cache->begin_transaction('users_sessions_'.$UserID); + $Cache->delete_row($SessionID); + $Cache->insert_front($SessionID,array( + 'SessionID'=>$SessionID, + 'Browser'=>$Browser, + 'OperatingSystem'=>$OperatingSystem, + 'IP'=>$_SERVER['REMOTE_ADDR'], + 'LastUpdate'=>sqltime() + )); + $Cache->commit_transaction(0); + } + + // Notifications + if(isset($LoggedUser['Permissions']['site_torrents_notify'])) { + $LoggedUser['Notify'] = $Cache->get_value('notify_filters_'.$LoggedUser['ID']); + if(!is_array($LoggedUser['Notify'])) { + $DB->query("SELECT ID, Label FROM users_notify_filters WHERE UserID='$LoggedUser[ID]'"); + $LoggedUser['Notify'] = $DB->to_array('ID'); + $Cache->cache_value('notify_filters_'.$LoggedUser['ID'], $LoggedUser['Notify'], 2592000); + } + } + + // We've never had to disable the wiki privs of anyone. + if ($LoggedUser['DisableWiki']) { + unset($LoggedUser['Permissions']['site_edit_wiki']); + } + + // IP changed + if($LoggedUser['IP'] != $_SERVER['REMOTE_ADDR'] && !check_perms('site_disable_ip_history')) { + if(site_ban_ip($_SERVER['REMOTE_ADDR'])) { + error('Your IP has been banned.'); + } + + $CurIP = db_string($LoggedUser['IP']); + $NewIP = db_string($_SERVER['REMOTE_ADDR']); + $DB->query("UPDATE users_history_ips SET + EndTime='".sqltime()."' + WHERE EndTime IS NULL + AND UserID='$LoggedUser[ID]' + AND IP='$CurIP'"); + $DB->query("INSERT IGNORE INTO users_history_ips + (UserID, IP, StartTime) VALUES + ('$LoggedUser[ID]', '$NewIP', '".sqltime()."')"); + + $ipcc = geoip($NewIP); + $DB->query("UPDATE users_main SET IP='$NewIP', ipcc='".$ipcc."' WHERE ID='$LoggedUser[ID]'"); + $Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']); + $Cache->update_row(false, array('IP' => $_SERVER['REMOTE_ADDR'])); + $Cache->commit_transaction(0); + + + } + + + + // Get stylesheets + $Stylesheets = $Cache->get_value('stylesheets'); + if (!is_array($Stylesheets)) { + $DB->query('SELECT ID, LOWER(REPLACE(Name," ","_")) AS Name, Name AS ProperName FROM stylesheets'); + $Stylesheets = $DB->to_array('ID', MYSQLI_BOTH); + $Cache->cache_value('stylesheets', $Stylesheets, 600); + } + + //A9 TODO: Clean up this messy solution + $LoggedUser['StyleName']=$Stylesheets[$LoggedUser['StyleID']]['Name']; + + if(empty($LoggedUser['Username'])) { + logout(); // Ghost + } +} + + +$Debug->set_flag('end user handling'); + +$Debug->set_flag('start function definitions'); + +// Get cached user info, is used for the user loading the page and usernames all over the site +function user_info($UserID) { + global $DB, $Cache; + $UserInfo = $Cache->get_value('user_info_'.$UserID); + // the !isset($UserInfo['Paranoia']) can be removed after a transition period + if(empty($UserInfo) || empty($UserInfo['ID']) || !isset($UserInfo['Paranoia'])) { + + + $DB->query("SELECT + m.ID, + m.Username, + m.PermissionID, + m.Paranoia, + i.Artist, + i.Donor, + i.Warned, + i.Avatar, + m.Enabled, + m.Title, + i.CatchupTime, + m.Visible + FROM users_main AS m + INNER JOIN users_info AS i ON i.UserID=m.ID + WHERE m.ID='$UserID'"); + if($DB->record_count() == 0) { // Deleted user, maybe? + $UserInfo = array('ID'=>'','Username'=>'','PermissionID'=>0,'Artist'=>false,'Donor'=>false,'Warned'=>'0000-00-00 00:00:00','Avatar'=>'','Enabled'=>0,'Title'=>'', 'CatchupTime'=>0, 'Visible'=>'1'); + + } else { + $UserInfo = $DB->next_record(MYSQLI_ASSOC, array('Paranoia', 'Title')); + $UserInfo['CatchupTime'] = strtotime($UserInfo['CatchupTime']); + $UserInfo['Paranoia'] = unserialize($UserInfo['Paranoia']); + if($UserInfo['Paranoia'] === false) { + $UserInfo['Paranoia'] = array(); + } + } + $Cache->cache_value('user_info_'.$UserID, $UserInfo, 2592000); + } + if(strtotime($UserInfo['Warned']) < time()) { + $UserInfo['Warned'] = '0000-00-00 00:00:00'; + $Cache->cache_value('user_info_'.$UserID, $UserInfo, 2592000); + } + + // Image proxy + if(check_perms('site_proxy_images') && !empty($UserInfo['Avatar'])) { + $UserInfo['Avatar'] = 'http'.($SSL?'s':'').'://'.SITE_URL.'/image.php?c=1&avatar='.$UserID.'&i='.urlencode($UserInfo['Avatar']); + } + return $UserInfo; +} + +// Only used for current user +function user_heavy_info($UserID) { + global $DB, $Cache; + $HeavyInfo = $Cache->get_value('user_info_heavy_'.$UserID); + + if(empty($HeavyInfo)) { + + $DB->query("SELECT + m.Invites, + m.torrent_pass, + m.IP, + m.CustomPermissions, + m.can_leech AS CanLeech, + i.AuthKey, + i.RatioWatchEnds, + i.RatioWatchDownload, + i.StyleID, + i.StyleURL, + i.DisableInvites, + i.DisablePosting, + i.DisableUpload, + i.DisableWiki, + i.DisableAvatar, + i.DisablePM, + i.DisableRequests, + i.SiteOptions, + i.DownloadAlt, + i.LastReadNews, + i.RestrictedForums, + i.PermittedForums, + m.FLTokens + FROM users_main AS m + INNER JOIN users_info AS i ON i.UserID=m.ID + WHERE m.ID='$UserID'"); + $HeavyInfo = $DB->next_record(MYSQLI_ASSOC, array('CustomPermissions', 'SiteOptions')); + + if (!empty($HeavyInfo['CustomPermissions'])) { + $HeavyInfo['CustomPermissions'] = unserialize($HeavyInfo['CustomPermissions']); + } else { + $HeavyInfo['CustomPermissions'] = array(); + } + + if (!empty($HeavyInfo['RestrictedForums'])) { + $RestrictedForums = explode(',', $HeavyInfo['RestrictedForums']); + } else { + $RestrictedForums = array(); + } + unset($HeavyInfo['RestrictedForums']); + if (!empty($HeavyInfo['PermittedForums'])) { + $PermittedForums = explode(',', $HeavyInfo['PermittedForums']); + } else { + $PermittedForums = array(); + } + unset($HeavyInfo['PermittedForums']); + if (!empty($PermittedForums) || !empty($RestrictedForums)) { + $HeavyInfo['CustomForums'] = array(); + foreach ($RestrictedForums as $ForumID) { + $HeavyInfo['CustomForums'][$ForumID] = 0; + } + foreach ($PermittedForums as $ForumID) { + $HeavyInfo['CustomForums'][$ForumID] = 1; + } + } else { + $HeavyInfo['CustomForums'] = null; + } + + $HeavyInfo['SiteOptions'] = unserialize($HeavyInfo['SiteOptions']); + if(!empty($HeavyInfo['SiteOptions'])) { + $HeavyInfo = array_merge($HeavyInfo, $HeavyInfo['SiteOptions']); + } + unset($HeavyInfo['SiteOptions']); + + $Cache->cache_value('user_info_heavy_'.$UserID, $HeavyInfo, 0); + } + return $HeavyInfo; +} + +function update_site_options($UserID, $NewOptions) { + if(!is_number($UserID)) { + error(0); + } + if(empty($NewOptions)) { + return false; + } + global $DB, $Cache, $LoggedUser; + + // Get SiteOptions + $DB->query("SELECT SiteOptions FROM users_info WHERE UserID = $UserID"); + list($SiteOptions) = $DB->next_record(MYSQLI_NUM,false); + $SiteOptions = unserialize($SiteOptions); + + // Get HeavyInfo + $HeavyInfo = user_heavy_info($UserID); + + // Insert new/replace old options + $SiteOptions = array_merge($SiteOptions, $NewOptions); + $HeavyInfo = array_merge($HeavyInfo, $NewOptions); + + // Update DB + $DB->query("UPDATE users_info SET SiteOptions = '".db_string(serialize($SiteOptions))."' WHERE UserID = $UserID"); + + // Update cache + $Cache->cache_value('user_info_heavy_'.$UserID, $HeavyInfo, 0); + + // Update $LoggedUser if the options are changed for the current + if($LoggedUser['ID'] == $UserID) { + $LoggedUser = array_merge($LoggedUser, $NewOptions); + $LoggedUser['ID'] = $UserID; // We don't want to allow userid switching + } +} + +function get_permissions($PermissionID) { + global $DB, $Cache; + $Permission = $Cache->get_value('perm_'.$PermissionID); + if(empty($Permission)) { + $DB->query("SELECT p.Level AS Class, p.Values as Permissions FROM permissions AS p WHERE ID='$PermissionID'"); + $Permission = $DB->next_record(MYSQLI_ASSOC, array('Permissions')); + $Permission['Permissions'] = unserialize($Permission['Permissions']); + $Cache->cache_value('perm_'.$PermissionID, $Permission, 2592000); + } + return $Permission; +} + +function get_permissions_for_user($UserID, $CustomPermissions = false) { + global $DB; + + $UserInfo = user_info($UserID); + + if ($CustomPermissions === false) { + $DB->query('SELECT um.CustomPermissions FROM users_main AS um WHERE um.ID = '.((int)$UserID)); + + list($CustomPermissions) = $DB->next_record(MYSQLI_NUM, false); + } + + if (!empty($CustomPermissions) && !is_array($CustomPermissions)) { + $CustomPermissions = unserialize($CustomPermissions); + } + + $Permissions = get_permissions($UserInfo['PermissionID']); + + + // Manage 'special' inherited permissions + if($UserInfo['Artist']) { + $ArtistPerms = get_permissions(ARTIST); + } else { + $ArtistPerms = array('Permissions' => array()); + } + + if($UserInfo['Donor']) { + $DonorPerms = get_permissions(DONOR); + } else { + $DonorPerms = array('Permissions' => array()); + } + + if(!empty($CustomPermissions)) { + $CustomPerms = $CustomPermissions; + } else { + $CustomPerms = array(); + } + + $MaxCollages = $Permissions['Permissions']['MaxCollages'] + $DonorPerms['Permissions']['MaxCollages'] + $ArtistPerms['Permissions']['MaxCollages'] + $CustomPerms['MaxCollages']; + + //Combine the permissions + return array_merge($Permissions['Permissions'], $DonorPerms['Permissions'], $ArtistPerms['Permissions'], $CustomPerms, array('MaxCollages' => $MaxCollages)); +} + +// This function is slow. Don't call it unless somebody's logging in. +function site_ban_ip($IP) { + global $DB, $Cache; + $IPNum = ip2unsigned($IP); + $IPBans = $Cache->get_value('ip_bans'); + if(!is_array($IPBans)) { + $DB->query("SELECT ID, FromIP, ToIP FROM ip_bans"); + $IPBans = $DB->to_array(0, MYSQLI_NUM); + $Cache->cache_value('ip_bans', $IPBans, 0); + } + foreach($IPBans as $Index => $IPBan) { + list($ID, $FromIP, $ToIP) = $IPBan; + if($IPNum >= $FromIP && $IPNum <= $ToIP) { + return true; + } + } + + return false; +} + + + +function ip2unsigned($IP) { + return sprintf("%u", ip2long($IP)); +} + +// Geolocate an IP address. Two functions - a database one, and a dns one. +function geoip($IP) { + static $IPs = array(); + if (isset($IPs[$IP])) { + return $IPs[$IP]; + } + $Long = ip2unsigned($IP); + if(!$Long || $Long == 2130706433) { // No need to check cc for 127.0.0.1 + return false; + } + global $DB; + $DB->query("SELECT EndIP,Code FROM geoip_country WHERE $Long >= StartIP ORDER BY StartIP DESC LIMIT 1"); + if((!list($EndIP,$Country) = $DB->next_record()) || $EndIP < $Long) { + $Country = '?'; + } + $IPs[$IP] = $Country; + return $Country; +} + +function old_geoip($IP) { + static $Countries = array(); + if(empty($Countries[$IP])) { + $Country = 0; + // Reverse IP, so 127.0.0.1 becomes 1.0.0.127 + $ReverseIP = implode('.', array_reverse(explode('.', $IP))); + $TestHost = $ReverseIP.'.country.netop.org'; + $Return = dns_get_record($TestHost, DNS_TXT); + if (!empty($Return)) { + $Country = $Return[0]['txt']; + } + if(!$Country) { + $Return = gethostbyaddr($IP); + $Return = explode('.',$Return); + $Return = array_pop($Return); + if(strlen($Return) == 2 && !is_number($Return)) { + $Country = strtoupper($Return); + } else { + $Country = '?'; + } + } + if($Country == 'UK') { $Country = 'GB'; } + $Countries[$IP] = $Country; + } + return $Countries[$IP]; +} + +function gethostbyip($ip) +{ + $testar = explode('.',$ip); + if (count($testar)!=4) { + return $ip; + } + for ($i=0;$i<4;++$i) { + if (!is_numeric($testar[$i])) { + return $ip; + } + } + + $host = `host -W 1 $ip`; + return (($host ? end ( explode (' ', $host)) : $ip)); +} + + +function get_host($IP) { + static $ID = 0; + ++$ID; + return 'Resolving host...'; +} + +function lookup_ip($IP) { + //TODO: use the $Cache + $Output = explode(' ',shell_exec('host -W 1 '.escapeshellarg($IP))); + if(count($Output) == 1 && empty($Output[0])) { + //No output at all implies the command failed + return ''; + } + + if(count($Output) != 5) { + return false; + } else { + return $Output[4]; + } +} + +function get_cc($IP) { + static $ID = 0; + ++$ID; + return 'Resolving CC...'; +} + +function display_ip($IP) { + $Line = display_str($IP).' ('.get_cc($IP).') '; + $Line .= '[S]'; + + return $Line; +} + +function logout() { + global $SessionID, $LoggedUser, $DB, $Cache; + setcookie('session','',time()-60*60*24*365,'/','',false); + setcookie('keeplogged','',time()-60*60*24*365,'/','',false); + setcookie('session','',time()-60*60*24*365,'/','',false); + if($SessionID) { + + + $DB->query("DELETE FROM users_sessions WHERE UserID='$LoggedUser[ID]' AND SessionID='".db_string($SessionID)."'"); + + $Cache->begin_transaction('users_sessions_'.$LoggedUser['ID']); + $Cache->delete_row($SessionID); + $Cache->commit_transaction(0); + } + $Cache->delete_value('user_info_'.$LoggedUser['ID']); + $Cache->delete_value('user_stats_'.$LoggedUser['ID']); + $Cache->delete_value('user_info_heavy_'.$LoggedUser['ID']); + + header('Location: login.php'); + + die(); +} + +function enforce_login() { + global $SessionID, $LoggedUser; + if (!$SessionID || !$LoggedUser) { + setcookie('redirect',$_SERVER['REQUEST_URI'],time()+60*30,'/','',false); + logout(); + } +} + +// Make sure $_GET['auth'] is the same as the user's authorization key +// Should be used for any user action that relies solely on GET. +function authorize($Ajax = false) { + global $LoggedUser; + if(empty($_REQUEST['auth']) || $_REQUEST['auth'] != $LoggedUser['AuthKey']) { + send_irc("PRIVMSG ".LAB_CHAN." :".$LoggedUser['Username']." just failed authorize on ".$_SERVER['REQUEST_URI']." coming from ".$_SERVER['HTTP_REFERER']); + error('Invalid authorization key. Go back, refresh, and try again.', $Ajax); + return false; + } + return true; +} + +// This function is to include the header file on a page. +// $JSIncludes is a comma separated list of js files to be inclides on +// the page, ONLY PUT THE RELATIVE LOCATION WITHOUT .js +// ex: 'somefile,somdire/somefile' + +function show_header($PageTitle='',$JSIncludes='') { + global $Document, $Cache, $DB, $LoggedUser, $Mobile, $Classes; + + if($PageTitle!='') { $PageTitle.=' :: '; } + $PageTitle .= SITE_NAME; + + if(!is_array($LoggedUser)) { + require(SERVER_ROOT.'/design/publicheader.php'); + } else { + require(SERVER_ROOT.'/design/privateheader.php'); + } +} + +/*-- show_footer function ------------------------------------------------*/ +/*------------------------------------------------------------------------*/ +/* This function is to include the footer file on a page. */ +/* $Options is an optional array that you can pass information to the */ +/* header through as well as setup certain limitations */ +/* Here is a list of parameters that work in the $Options array: */ +/* ['disclaimer'] = [boolean] Displays the disclaimer in the footer */ +/* Default is false */ +/**************************************************************************/ +function show_footer($Options=array()) { + global $ScriptStartTime, $LoggedUser, $Cache, $DB, $SessionID, $UserSessions, $Debug, $Time; + if (!is_array($LoggedUser)) { require(SERVER_ROOT.'/design/publicfooter.php'); } + else { require(SERVER_ROOT.'/design/privatefooter.php'); } +} + +function cut_string($Str,$Length,$Hard=0,$ShowDots=1) { + if (strlen($Str)>$Length) { + if ($Hard==0) { + // Not hard, cut at closest word + $CutDesc=substr($Str,0,$Length); + $DescArr=explode(' ',$CutDesc); + $DescArr=array_slice($DescArr,0,count($DescArr)-1); + $CutDesc=implode($DescArr,' '); + if ($ShowDots==1) { $CutDesc.='...'; } + } else { + $CutDesc=substr($Str,0,$Length); + if ($ShowDots==1) { $CutDesc.='...'; } + } + return $CutDesc; + } else { + return $Str; + } +} + +function get_ratio_color($Ratio) { + if ($Ratio < 0.1) { return 'r00'; } + if ($Ratio < 0.2) { return 'r01'; } + if ($Ratio < 0.3) { return 'r02'; } + if ($Ratio < 0.4) { return 'r03'; } + if ($Ratio < 0.5) { return 'r04'; } + if ($Ratio < 0.6) { return 'r05'; } + if ($Ratio < 0.7) { return 'r06'; } + if ($Ratio < 0.8) { return 'r07'; } + if ($Ratio < 0.9) { return 'r08'; } + if ($Ratio < 1) { return 'r09'; } + if ($Ratio < 2) { return 'r10'; } + if ($Ratio < 5) { return 'r20'; } + return 'r50'; +} + +function ratio($Dividend, $Divisor, $Color = true) { + if($Divisor == 0 && $Dividend == 0) { + return '--'; + } elseif($Divisor == 0) { + return '∞'; + } + $Ratio = number_format(max($Dividend/$Divisor-0.005,0), 2); //Subtract .005 to floor to 2 decimals + if($Color) { + $Class = get_ratio_color($Ratio); + if($Class) { + $Ratio = ''.$Ratio.''; + } + } + return $Ratio; + +} + +function get_url($Exclude = false) { + if($Exclude !== false) { + $QueryItems = array(); + parse_str($_SERVER['QUERY_STRING'], $QueryItems); + + foreach($QueryItems AS $Key => $Val) { + if(!in_array(strtolower($Key),$Exclude)) { + $Query[$Key] = $Val; + } + } + + if(empty($Query)) { + return; + } + return display_str(http_build_query($Query)); + } else { + return display_str($_SERVER['QUERY_STRING']); + } +} + +/** + * Finds what page we're on and gives it to us, as well as the LIMIT clause for SQL + * Takes in $_GET['page'] as an additional input + * + * @param $PerPage Results to show per page + * + * @param $DefaultResult Optional, which result's page we want if no page is specified + * If this parameter is not specified, we will default to page 1 + * + * @return array(int,string) What page we are on, and what to use in the LIMIT section of a query + * i.e. "SELECT [...] LIMIT $Limit;" + */ +function page_limit($PerPage, $DefaultResult = 1) { + if(!isset($_GET['page'])) { + $Page = ceil($DefaultResult/$PerPage); + if($Page == 0) $Page = 1; + $Limit=$PerPage; + } else { + if(!is_number($_GET['page'])) { + error(0); + } + $Page = $_GET['page']; + if ($Page == 0) { $Page = 1; } + $Limit=$PerPage*$_GET['page']-$PerPage . ', ' . $PerPage; + } + return array($Page,$Limit); +} + +// For data stored in memcached catalogues (giant arrays), eg. forum threads +function catalogue_limit($Page,$PerPage,$CatalogueSize=500) { + $CatalogueID = floor(($PerPage*$Page-$PerPage)/$CatalogueSize);; + $CatalogueLimit = ($CatalogueID*$CatalogueSize).', '.$CatalogueSize; + return array($CatalogueID,$CatalogueLimit); +} + +function catalogue_select($Catalogue,$Page,$PerPage,$CatalogueSize=500) { + return array_slice($Catalogue,(($PerPage*$Page-$PerPage)%$CatalogueSize),$PerPage,true); +} + +function get_pages($StartPage,$TotalRecords,$ItemsPerPage,$ShowPages=11,$Anchor='') { + global $Document, $Method, $Mobile; + $Location = $Document.'.php'; + /*-- Get pages ---------------------------------------------------------------// + This function returns a page list, given certain information about the pages. + + Explanation of arguments: + * $StartPage: The current record the page you're on starts with. + eg. if you're on page 2 of a forum thread with 25 posts per page, $StartPage is 25. + If you're on page 1, $StartPage is 0. + * $TotalRecords: The total number of records in the result set. + eg. if you're on a forum thread with 152 posts, $TotalRecords is 152. + * $ItemsPerPage: Self-explanatory. The number of records shown on each page + eg. if there are 25 posts per forum page, $ItemsPerPage is 25. + $ShowPages: The number of page links that are shown. + eg. If there are 20 pages that exist, but $ShowPages is only 11, only 11 links will be shown. + //----------------------------------------------------------------------------*/ + $StartPage=ceil($StartPage); + if ($StartPage==0) { $StartPage=1; } + $TotalPages = 0; + if ($TotalRecords>0) { + if ($StartPage>ceil($TotalRecords/$ItemsPerPage)) { $StartPage=ceil($TotalRecords/$ItemsPerPage); } + + $ShowPages--; + $TotalPages=ceil($TotalRecords/$ItemsPerPage); + + if ($TotalPages>$ShowPages) { + $StartPosition=$StartPage-round($ShowPages/2); + + if ($StartPosition<=0) { + $StartPosition=1; + } else { + if ($StartPosition>=($TotalPages-$ShowPages)) { + $StartPosition=$TotalPages-$ShowPages; + } + } + + $StopPage=$ShowPages+$StartPosition; + + } else { + $StopPage=$TotalPages; + $StartPosition=1; + } + + if ($StartPosition<1) { $StartPosition=1; } + + $QueryString = get_url(array('page','post')); + if($QueryString != '') { $QueryString = '&'.$QueryString; } + + $Pages = ''; + + if ($StartPage>1) { + $Pages.='<< First '; + $Pages.='< Prev | '; + } + //End change + + if (!$Mobile) { + for ($i=$StartPosition; $i<=$StopPage; $i++) { + //if ($i!=$StartPage) { $Pages.=''; } + if ($i!=$StartPage) { $Pages.=''; } + $Pages.=""; + if($i*$ItemsPerPage>$TotalRecords) { + $Pages.=((($i-1)*$ItemsPerPage)+1).'-'.($TotalRecords); + } else { + $Pages.=((($i-1)*$ItemsPerPage)+1).'-'.($i*$ItemsPerPage); + } + + $Pages.=""; + if ($i!=$StartPage) { $Pages.=''; } + if ($i<$StopPage) { $Pages.=" | "; } + } + } else { + $Pages .= $StartPage; + } + + if ($StartPage<$TotalPages) { + $Pages.=' | Next > '; + $Pages.=' Last >>'; + } + + } + + if ($TotalPages>1) { return $Pages; } + +} + +function send_email($To,$Subject,$Body,$From='noreply',$ContentType='text/plain') { + $Headers='MIME-Version: 1.0'."\r\n"; + $Headers.='Content-type: '.$ContentType.'; charset=iso-8859-1'."\r\n"; + $Headers.='From: '.SITE_NAME.' <'.$From.'@'.NONSSL_SITE_URL.'>'."\r\n"; + $Headers.='Reply-To: '.$From.'@'.NONSSL_SITE_URL."\r\n"; + $Headers.='X-Mailer: Project Gazelle'."\r\n"; + $Headers.='Message-Id: <'.make_secret().'@'.NONSSL_SITE_URL.">\r\n"; + $Headers.='X-Priority: 3'."\r\n"; + mail($To,$Subject,$Body,$Headers,"-f ".$From."@".NONSSL_SITE_URL); +} + +function get_size($Size, $Levels = 2) { + $Units = array(' B',' KB',' MB',' GB',' TB',' PB',' EB',' ZB',' YB'); + $Size = (double) $Size; + for($Steps = 0; abs($Size) >= 1024; $Size /= 1024, $Steps++) {} + if(func_num_args() == 1 && $Steps >= 4) { + $Levels++; + } + return number_format($Size,$Levels).$Units[$Steps]; +} + +function get_bytes($Size) { + list($Value,$Unit) = sscanf($Size, "%f%s"); + $Unit = ltrim($Unit); + if(empty($Unit)) { + return $Value ? round($Value) : 0; + } + switch(strtolower($Unit[0])) { + case 'k': return round($Value * 1024); + case 'm': return round($Value * 1048576); + case 'g': return round($Value * 1073741824); + case 't': return round($Value * 1099511627776); + default: return 0; + } +} + +function human_format($Number) { + $Steps = 0; + while($Number>=1000) { + $Steps++; + $Number=$Number/1000; + } + switch ($Steps) { + case 0: return round($Number); break; + case 1: return round($Number,2).'k'; break; + case 2: return round($Number,2).'M'; break; + case 3: return round($Number,2).'G'; break; + case 4: return round($Number,2).'T'; break; + case 5: return round($Number,2).'P'; break; + default: + return round($Number,2).'E + '.$Steps*3; + } +} + +function is_number($Str) { + $Return = true; + if ($Str < 0) { $Return = false; } + // We're converting input to a int, then string and comparing to original + $Return = ($Str == strval(intval($Str)) ? true : false); + return $Return; +} + +function file_string($EscapeStr) { + return str_replace(array('"','*','/',':','<','>','?','\\','|'), '', $EscapeStr); +} + +// This is preferable to htmlspecialchars because it doesn't screw up upon a double escape +function display_str($Str) { + if ($Str === NULL || $Str === FALSE || is_array($Str)) { + return ''; + } + if ($Str!='' && !is_number($Str)) { + $Str=make_utf8($Str); + $Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8"); + $Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&",$Str); + + $Replace = array( + "'",'"',"<",">", + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $With=array( + ''','"','<','>', + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $Str=str_replace($Replace,$With,$Str); + } + return $Str; +} + +// Use sparingly +function undisplay_str($Str) { + return mb_convert_encoding($Str, 'UTF-8', 'HTML-ENTITIES'); +} + +function make_utf8($Str) { + if ($Str!="") { + if (is_utf8($Str)) { $Encoding="UTF-8"; } + if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); } + if (empty($Encoding)) { $Encoding="ISO-8859-1"; } + if ($Encoding=="UTF-8") { return $Str; } + else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); } + } +} + +function is_utf8($Str) { + return preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] // ASCII + | [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16 + )*$%xs', $Str + ); +} + +// Escape an entire array for output +// $Escape is either true, false, or a list of array keys to not escape +function display_array($Array, $Escape = array()) { + foreach ($Array as $Key => $Val) { + if((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) { + $Array[$Key] = display_str($Val); + } + } + return $Array; +} + +// Gets a tag ready for database input and display +function sanitize_tag($str) { + $str = strtolower($str); + $str = preg_replace('/[^a-z0-9.]/', '', $str); + $str = htmlspecialchars($str); + $str = db_string(trim($str)); + return $str; +} + +// Generate a random string +function make_secret($Length = 32) { + $Secret = ''; + $Chars='abcdefghijklmnopqrstuvwxyz0123456789'; + for($i=0; $i<$Length; $i++) { + $Rand = mt_rand(0, strlen($Chars)-1); + $Secret .= substr($Chars, $Rand, 1); + } + return str_shuffle($Secret); +} + +//TODO: Read and add this one +/* +function make_secret($Length = 32) { + $Secret = ''; + $Chars='abcdefghijklmnopqrstuvwxyz0123456789'; + $CharLen = strlen($Chars)-1; + for ($i = 0; $i < $Length; ++$i) { + $Secret .= $Chars[mt_rand(0, $CharLen)]; + } + return $Secret; +} +*/ + +// Password hashes, feel free to make your own algorithm here +function make_hash($Str,$Secret) { + return sha1(md5($Secret).$Str.sha1($Secret).SITE_SALT); +} + +/* +Returns a username string for display +$Class and $Title can be omitted for an abbreviated version +$IsDonor, $IsWarned and $IsEnabled can be omitted for a *very* abbreviated version +*/ +function format_username($UserID, $Username, $IsDonor = false, $IsWarned = '0000-00-00 00:00:00', $IsEnabled = true, $Class = false, $Title = false) { + if($UserID == 0) { + return 'System'; + } elseif($Username == '') { + return "Unknown [$UserID]"; + } + $str=''.$Username.''; + $str.=($IsDonor) ? 'Donor' : ''; + + + $str.=($IsWarned!='0000-00-00 00:00:00') ? 'Warned' : ''; + $str.=(!$IsEnabled) ? 'Banned' : ''; + + $str.=($Class) ? ' ('.make_class_string($Class).')' : ''; + $str.=($Title) ? ' ('.$Title.')' : ''; + return $str; +} + +function make_class_string($ClassID) { + global $Classes; + return $Classes[$ClassID]['Name']; +} + +//Write to the group log +function write_group_log($GroupID, $TorrentID, $UserID, $Message, $Hidden) { + global $DB,$Time; + $DB->query("INSERT INTO group_log (GroupID, TorrentID, UserID, Info, Time, Hidden) VALUES (".$GroupID.", ".$TorrentID.", ".$UserID.", '".db_string($Message)."', '".sqltime()."', ".$Hidden.")"); +} + +// Write a message to the system log +function write_log($Message) { + global $DB,$Time; + $DB->query('INSERT INTO log (Message, Time) VALUES (\''.db_string($Message).'\', \''.sqltime().'\')'); +} + +// Send a message to an IRC bot listening on SOCKET_LISTEN_PORT +function send_irc($Raw) { + $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT); + $Raw = str_replace(array("\n", "\r"), '', $Raw); + fwrite($IRCSocket, $Raw); + fclose($IRCSocket); +} + +function delete_torrent($ID, $GroupID=0) { + global $DB, $Cache, $LoggedUser; + if(!$GroupID) { + $DB->query("SELECT GroupID, UserID FROM torrents WHERE ID='$ID'"); + list($GroupID, $UploaderID) = $DB->next_record(); + + } + if(empty($UserID)) { + $DB->query("SELECT UserID FROM torrents WHERE ID='$ID'"); + list($UserID) = $DB->next_record(); + } + + $RecentUploads = $Cache->get_value('recent_uploads_'.$UserID); + if(is_array($RecentUploads)) { + foreach($RecentUploads as $Key => $Recent) { + if($Recent['ID'] == $GroupID) { + $Cache->delete_value('recent_uploads_'.$UserID); + } + } + } + + + $DB->query("SELECT info_hash FROM torrents WHERE ID = ".$ID); + list($InfoHash) = $DB->next_record(MYSQLI_BOTH, false); + $DB->query("DELETE FROM torrents WHERE ID = ".$ID); + update_tracker('delete_torrent', array('info_hash' => rawurlencode($InfoHash), 'id' => $ID)); + + $Cache->decrement('stats_torrent_count'); + + $DB->query("SELECT COUNT(ID) FROM torrents WHERE GroupID='$GroupID' AND flags <> 1"); + list($Count) = $DB->next_record(); + + if($Count == 0) { + delete_group($GroupID); + } else { + update_hash($GroupID); + //Artists + $DB->query("SELECT ArtistID + FROM torrents_artists + WHERE GroupID = ".$GroupID); + $ArtistIDs = $DB->collect('ArtistID'); + foreach($ArtistIDs as $ArtistID) { + $Cache->delete_value('artist_'.$ArtistID); + } + } + + // Torrent notifications + $DB->query("SELECT UserID FROM users_notify_torrents WHERE TorrentID='$ID'"); + while(list($UserID) = $DB->next_record()) { + $Cache->delete_value('notifications_new_'.$UserID); + } + $DB->query("DELETE FROM users_notify_torrents WHERE TorrentID='$ID'"); + + + $DB->query("UPDATE reportsv2 SET + Status='Resolved', + LastChangeTime='".sqltime()."', + ModComment='Report already dealt with (Torrent deleted)' + WHERE TorrentID=".$ID." + AND Status != 'Resolved'"); + $Reports = $DB->affected_rows(); + if($Reports) { + $Cache->decrement('num_torrent_reportsv2', $Reports); + } + + $DB->query("DELETE FROM torrents_files WHERE TorrentID='$ID'"); + $DB->query("DELETE FROM torrents_bad_tags WHERE TorrentID = ".$ID); + $DB->query("DELETE FROM torrents_bad_folders WHERE TorrentID = ".$ID); + $DB->query("DELETE FROM torrents_bad_files WHERE TorrentID = ".$ID); + $DB->query("DELETE FROM torrents_cassette_approved WHERE TorrentID = ".$ID); + $DB->query("DELETE FROM torrents_lossymaster_approved WHERE TorrentID = ".$ID); + $Cache->delete_value('torrent_download_'.$ID); + $Cache->delete_value('torrent_group_'.$GroupID); + $Cache->delete_value('torrents_details_'.$GroupID); +} + +function delete_group($GroupID) { + global $DB, $Cache; + + write_log("Group ".$GroupID." automatically deleted (No torrents have this group)."); + //$DB->query("DELETE FROM group_log WHERE GroupID = ".$GroupID); + + //Never call this unless you're certain the group is no longer used by any torrents + $DB->query("SELECT CategoryID FROM torrents_group WHERE ID='$GroupID'"); + list($Category) = $DB->next_record(); + if($Category == 1) { + $Cache->decrement('stats_album_count'); + } + $Cache->decrement('stats_group_count'); + + + + // Collages + $DB->query("SELECT CollageID FROM collages_torrents WHERE GroupID='$GroupID'"); + if($DB->record_count()>0) { + $CollageIDs = $DB->collect('CollageID'); + $DB->query("UPDATE collages SET NumTorrents=NumTorrents-1 WHERE ID IN (".implode(', ',$CollageIDs).")"); + $DB->query("DELETE FROM collages_torrents WHERE GroupID='$GroupID'"); + + foreach($CollageIDs as $CollageID) { + $Cache->delete_value('collage_'.$CollageID); + } + $Cache->delete_value('torrent_collages_'.$GroupID); + } + + //Artists + //Collect the artist IDs and then wipe the torrents_artist entry + $DB->query("SELECT ArtistID FROM torrents_artists WHERE GroupID = ".$GroupID); + $Artists = $DB->collect('ArtistID'); + + $DB->query("DELETE FROM torrents_artists WHERE GroupID='$GroupID'"); + + foreach($Artists as $ArtistID) { + if(empty($ArtistID)) { continue; } + //Get a count of how many groups or requests use the artist ID + $DB->query("SELECT COUNT(ag.ArtistID) + FROM artists_group as ag + LEFT JOIN requests_artists AS ra ON ag.ArtistID=ra.ArtistID + WHERE ra.ArtistID IS NOT NULL + AND ag.ArtistID = '$ArtistID'"); + list($ReqCount) = $DB->next_record(); + $DB->query("SELECT COUNT(ag.ArtistID) + FROM artists_group as ag + LEFT JOIN torrents_artists AS ta ON ag.ArtistID=ta.ArtistID + WHERE ta.ArtistID IS NOT NULL + AND ag.ArtistID = '$ArtistID'"); + list($GroupCount) = $DB->next_record(); + if(($ReqCount + $GroupCount) == 0) { + //The only group to use this artist + delete_artist($ArtistID); + } else { + //Not the only group, still need to clear cache + $Cache->delete_value('artist_'.$ArtistID); + } + } + + // Requests + $DB->query("SELECT ID FROM requests WHERE GroupID='$GroupID'"); + $Requests = $DB->collect('ID'); + $DB->query("UPDATE requests SET GroupID = NULL WHERE GroupID = '$GroupID'"); + foreach ($Requests as $RequestID) { + $Cache->delete_value('request_'.$RequestID); + } + + $DB->query("DELETE FROM torrents_group WHERE ID='$GroupID'"); + $DB->query("DELETE FROM torrents_tags WHERE GroupID='$GroupID'"); + $DB->query("DELETE FROM torrents_tags_votes WHERE GroupID='$GroupID'"); + $DB->query("DELETE FROM torrents_comments WHERE GroupID='$GroupID'"); + $DB->query("DELETE FROM bookmarks_torrents WHERE GroupID='$GroupID'"); + $DB->query("DELETE FROM wiki_torrents WHERE PageID='$GroupID'"); + $DB->query("REPLACE INTO sphinx_delta (ID,Time) VALUES ('$GroupID',UNIX_TIMESTAMP())"); // Tells Sphinx that the group is removed + + $Cache->delete_value('torrents_details_'.$GroupID); + $Cache->delete_value('torrent_group_'.$GroupID); + $Cache->delete_value('groups_artists_'.$GroupID); +} + +function delete_artist($ArtistID) { + global $DB, $LoggedUser, $Cache; + + $DB->query("SELECT Name FROM artists_group WHERE ArtistID = ".$ArtistID); + list($Name) = $DB->next_record(); + + // Delete requests + $DB->query("SELECT RequestID FROM requests_artists WHERE ArtistID=".$ArtistID." AND ArtistID != 0"); + $Requests = $DB->to_array(); + foreach($Requests AS $Request) { + list($RequestID) = $Request; + $DB->query('DELETE FROM requests WHERE ID='.$RequestID); + $DB->query('DELETE FROM requests_votes WHERE RequestID='.$RequestID); + $DB->query('DELETE FROM requests_tags WHERE RequestID='.$RequestID); + $DB->query('DELETE FROM requests_artists WHERE RequestID='.$RequestID); + } + + // Delete artist + $DB->query('DELETE FROM artists_group WHERE ArtistID='.$ArtistID); + $DB->query('DELETE FROM artists_alias WHERE ArtistID='.$ArtistID); + $Cache->decrement('stats_artist_count'); + + // Delete wiki revisions + $DB->query('DELETE FROM wiki_artists WHERE PageID='.$ArtistID); + + // Delete tags + $DB->query('DELETE FROM artists_tags WHERE ArtistID='.$ArtistID); + + $Cache->delete_value('artist_'.$ArtistID); + // Record in log + + if(!empty($LoggedUser['Username'])) { + $Username = $LoggedUser['Username']; + } else { + $Username = 'System'; + } + write_log('Artist '.$ArtistID.' ('.$Name.') was deleted by '.$Username); +} + +function warn_user($UserID, $Duration, $Reason) { + global $LoggedUser, $DB, $Cache, $Time; + + $DB->query("SELECT Warned FROM users_info WHERE UserID=".$UserID." AND Warned <> '0000-00-00 00:00:00'"); + if($DB->record_count() > 0) { + //User was already warned, appending new warning to old. + list($OldDate) = $DB->next_record(); + $NewExpDate = date('Y-m-d H:i:s', strtotime($OldDate) + $Duration); + + send_pm($UserID, 0, db_string("You have received multiple warnings."), db_string("When you received your latest warning (Set to expire on ".date("Y-m-d", (time() + $Duration))."), you already had a different warning (Set to expire on ".date("Y-m-d", strtotime($OldDate)).").\n\n Due to this collision, your warning status will now expire at ".$NewExpDate.".")); + + $AdminComment = date("Y-m-d").' - Warning (Clash) extended to expire at '.$NewExpDate.' by '.$LoggedUser['Username']."\nReason: $Reason\n\n"; + + $DB->query('UPDATE users_info SET + Warned=\''.db_string($NewExpDate).'\', + WarnedTimes=WarnedTimes+1, + AdminComment=CONCAT(\''.db_string($AdminComment).'\',AdminComment) + WHERE UserID=\''.db_string($UserID).'\''); + } else { + //Not changing, user was not already warned + $WarnTime = time_plus($Duration); + + $Cache->begin_transaction('user_info_'.$UserID); + $Cache->update_row(false, array('Warned' => $WarnTime)); + $Cache->commit_transaction(0); + + $AdminComment = date("Y-m-d").' - Warned until '.$WarnTime.' by '.$LoggedUser['Username']."\nReason: $Reason\n\n"; + + $DB->query('UPDATE users_info SET + Warned=\''.db_string($WarnTime).'\', + WarnedTimes=WarnedTimes+1, + AdminComment=CONCAT(\''.db_string($AdminComment).'\',AdminComment) + WHERE UserID=\''.db_string($UserID).'\''); + } +} + +/*-- update_hash function ------------------------------------------------*/ +/*------------------------------------------------------------------------*/ +/* This function is to update the cache and sphinx delta index to keep */ +/* everything up to date */ +/*-- TODO ----------------------------------------------------------------*/ +/* Add in tag sorting based on positive negative votes algo */ +/**************************************************************************/ + +function update_hash($GroupID) { + global $DB,$SpecialChars,$Cache; + $DB->query("UPDATE torrents_group SET TagList=(SELECT REPLACE(GROUP_CONCAT(tags.Name SEPARATOR ' '),'.','_') + FROM torrents_tags AS t + INNER JOIN tags ON tags.ID=t.TagID + WHERE t.GroupID='$GroupID' + GROUP BY t.GroupID) + WHERE ID='$GroupID'"); + + $DB->query("REPLACE INTO sphinx_delta (ID, GroupName, TagList, Year, CategoryID, Time, ReleaseType, CatalogueNumber, Size, Snatched, Seeders, Leechers, LogScore, Scene, HasLog, HasCue, FreeTorrent, Media, Format, Encoding, RemasterTitle, FileList) + SELECT + g.ID AS ID, + g.Name AS GroupName, + g.TagList, + g.Year, + g.CategoryID, + UNIX_TIMESTAMP(g.Time) AS Time, + g.ReleaseType, + g.CatalogueNumber, + MAX(CEIL(t.Size/1024)) AS Size, + SUM(t.Snatched) AS Snatched, + SUM(t.Seeders) AS Seeders, + SUM(t.Leechers) AS Leechers, + MAX(t.LogScore) AS LogScore, + MAX(t.Scene) AS Scene, + MAX(t.HasLog) AS HasLog, + MAX(t.HasCue) AS HasCue, + BIT_OR(t.FreeTorrent-1) AS FreeTorrent, + GROUP_CONCAT(DISTINCT t.Media SEPARATOR ' ') AS Media, + GROUP_CONCAT(DISTINCT t.Format SEPARATOR ' ') AS Format, + GROUP_CONCAT(DISTINCT t.Encoding SEPARATOR ' ') AS Encoding, + GROUP_CONCAT(DISTINCT t.RemasterTitle SEPARATOR ' ') AS RemasterTitle, + GROUP_CONCAT(REPLACE(REPLACE(FileList, '|||', '\n '), '_', ' ') SEPARATOR '\n ') AS FileList + FROM torrents AS t + JOIN torrents_group AS g ON g.ID=t.GroupID + WHERE g.ID=$GroupID + GROUP BY g.ID"); + + $DB->query("INSERT INTO sphinx_delta + (ID, ArtistName) + SELECT + GroupID, + GROUP_CONCAT(aa.Name separator ' ') + FROM torrents_artists AS ta + JOIN artists_alias AS aa ON aa.AliasID=ta.AliasID + JOIN torrents_group AS tg ON tg.ID=ta.GroupID + WHERE ta.GroupID=$GroupID AND ta.Importance IN ('1', '4', '5', '6') + GROUP BY tg.ID + ON DUPLICATE KEY UPDATE ArtistName=values(ArtistName)"); + + $Cache->delete_value('torrents_details_'.$GroupID); + $Cache->delete_value('torrent_group_'.$GroupID); + + $ArtistInfo = get_artist($GroupID); + foreach($ArtistInfo as $Importances => $Importance) { + foreach($Importance as $Artist) { + $Cache->delete_value('artist_'.$Artist['id']); //Needed for at least freeleech change, if not others. + } + } + + $Cache->delete_value('groups_artists_'.$GroupID); +} + +// this function sends a PM to the userid $ToID and from the userid $FromID, sets date to now +// this function no longer uses db_string() so you will need to escape strings before using this function! +// set userid to 0 for a PM from 'system' +// if $ConvID is not set, it auto increments it, ie. starting a new conversation +function send_pm($ToID,$FromID,$Subject,$Body,$ConvID='') { + global $DB, $Cache, $Time; + if($ToID==0) { + // Don't allow users to send messages to the system + return; + } + if($ConvID=='') { + $DB->query("INSERT INTO pm_conversations(Subject) VALUES ('".$Subject."')"); + $ConvID = $DB->inserted_id(); + $DB->query("INSERT INTO pm_conversations_users + (UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES + ('$ToID', '$ConvID', '1','0','".sqltime()."', '".sqltime()."', '1')"); + if ($FromID != 0) { + $DB->query("INSERT INTO pm_conversations_users + (UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES + ('$FromID', '$ConvID', '0','1','".sqltime()."', '".sqltime()."', '0')"); + } + $ToID = array($ToID); + } else { + $DB->query("UPDATE pm_conversations_users SET + InInbox='1', + UnRead='1', + ReceivedDate='".sqltime()."' + WHERE UserID IN (".implode(',', $ToID).") + AND ConvID='$ConvID'"); + + $DB->query("UPDATE pm_conversations_users SET + InSentbox='1', + SentDate='".sqltime()."' + WHERE UserID='$FromID' + AND ConvID='$ConvID'"); + } + $DB->query("INSERT INTO pm_messages + (SenderID, ConvID, SentDate, Body) VALUES + ('$FromID', '$ConvID', '".sqltime()."', '".$Body."')"); + + // Clear the caches of the inbox and sentbox + //$DB->query("SELECT UnRead from pm_conversations_users WHERE ConvID='$ConvID' AND UserID='$ToID'"); + foreach($ToID as $ID) { + $DB->query("SELECT COUNT(ConvID) FROM pm_conversations_users WHERE UnRead = '1' and UserID='$ID' AND InInbox = '1'"); + list($UnRead) = $DB->next_record(); + $Cache->cache_value('inbox_new_'.$ID, $UnRead); + } + + //if ($UnRead == 0) { + // $Cache->increment('inbox_new_'.$ToID); + //} + return $ConvID; +} + +//Create thread function, things should already be escaped when sent here. +//Almost all the code is stolen straight from the forums and tailored for new posts only +function create_thread($ForumID, $AuthorID, $Title, $PostBody) { + global $DB, $Cache, $Time; + if(!$ForumID || !$AuthorID || !is_number($AuthorID) || !$Title || !$PostBody) { + return -1; + } + + $DB->query("SELECT Username FROM users_main WHERE ID=".$AuthorID); + if($DB->record_count() < 1) { + return -2; + } + list($AuthorName) = $DB->next_record(); + + $ThreadInfo = array(); + $ThreadInfo['IsLocked'] = 0; + $ThreadInfo['IsSticky'] = 0; + + $DB->query("INSERT INTO forums_topics + (Title, AuthorID, ForumID, LastPostTime, LastPostAuthorID) + Values + ('".$Title."', '".$AuthorID."', '$ForumID', '".sqltime()."', '".$AuthorID."')"); + $TopicID = $DB->inserted_id(); + $Posts = 1; + + $DB->query("INSERT INTO forums_posts + (TopicID, AuthorID, AddedTime, Body) + VALUES + ('$TopicID', '".$AuthorID."', '".sqltime()."', '".$PostBody."')"); + $PostID = $DB->inserted_id(); + + $DB->query("UPDATE forums SET + NumPosts = NumPosts+1, + NumTopics = NumTopics+1, + LastPostID = '$PostID', + LastPostAuthorID = '".$AuthorID."', + LastPostTopicID = '$TopicID', + LastPostTime = '".sqltime()."' + WHERE ID = '$ForumID'"); + + $DB->query("UPDATE forums_topics SET + NumPosts = NumPosts+1, + LastPostID = '$PostID', + LastPostAuthorID = '".$AuthorID."', + LastPostTime = '".sqltime()."' + WHERE ID = '$TopicID'"); + + // Bump this topic to head of the cache + list($Forum,,,$Stickies) = $Cache->get_value('forums_'.$ForumID); + if (!empty($Forum)) { + if (count($Forum) == TOPICS_PER_PAGE && $Stickies < TOPICS_PER_PAGE) { + array_pop($Forum); + } + $DB->query("SELECT f.IsLocked, f.IsSticky, f.NumPosts FROM forums_topics AS f WHERE f.ID ='$TopicID'"); + list($IsLocked,$IsSticky,$NumPosts) = $DB->next_record(); + $Part1 = array_slice($Forum,0,$Stickies,true); //Stickys + $Part2 = array( + $TopicID=>array( + 'ID' => $TopicID, + 'Title' => $Title, + 'AuthorID' => $AuthorID, + 'AuthorUsername' => $AuthorName, + 'IsLocked' => $IsLocked, + 'IsSticky' => $IsSticky, + 'NumPosts' => $NumPosts, + 'LastPostID' => $PostID, + 'LastPostTime' => sqltime(), + 'LastPostAuthorID' => $AuthorID, + 'LastPostUsername' => $AuthorName + ) + ); //Bumped thread + $Part3 = array_slice($Forum,$Stickies,TOPICS_PER_PAGE,true); //Rest of page + if ($Stickies > 0) { + $Part1 = array_slice($Forum,0,$Stickies,true); //Stickies + $Part3 = array_slice($Forum,$Stickies,TOPICS_PER_PAGE-$Stickies-1,true); //Rest of page + } else { + $Part1 = array(); + $Part3 = $Forum; + } + if (is_null($Part1)) { $Part1 = array(); } + if (is_null($Part3)) { $Part3 = array(); } + $Forum = $Part1 + $Part2 + $Part3; + $Cache->cache_value('forums_'.$ForumID, array($Forum,'',0,$Stickies), 0); + } + + //Update the forum root + $Cache->begin_transaction('forums_list'); + $UpdateArray = array( + 'NumPosts'=>'+1', + 'LastPostID'=>$PostID, + 'LastPostAuthorID'=>$AuthorID, + 'Username'=>$AuthorName, + 'LastPostTopicID'=>$TopicID, + 'LastPostTime'=>sqltime(), + 'Title'=>$Title, + 'IsLocked'=>$ThreadInfo['IsLocked'], + 'IsSticky'=>$ThreadInfo['IsSticky'] + ); + + $UpdateArray['NumTopics']='+1'; + + $Cache->update_row($ForumID, $UpdateArray); + $Cache->commit_transaction(0); + + $CatalogueID = floor((POSTS_PER_PAGE*ceil($Posts/POSTS_PER_PAGE)-POSTS_PER_PAGE)/THREAD_CATALOGUE); + $Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID); + $Post = array( + 'ID'=>$PostID, + 'AuthorID'=>$LoggedUser['ID'], + 'AddedTime'=>sqltime(), + 'Body'=>$PostBody, + 'EditedUserID'=>0, + 'EditedTime'=>'0000-00-00 00:00:00', + 'Username'=>'' + ); + $Cache->insert('', $Post); + $Cache->commit_transaction(0); + + $Cache->begin_transaction('thread_'.$TopicID.'_info'); + $Cache->update_row(false, array('Posts'=>'+1', 'LastPostAuthorID'=>$AuthorID)); + $Cache->commit_transaction(0); + + return $TopicID; +} + + + +// Check to see if a user has the permission to perform an action +function check_perms($PermissionName,$MinClass = 0) { + global $LoggedUser; + return (isset($LoggedUser['Permissions'][$PermissionName]) && $LoggedUser['Permissions'][$PermissionName] && $LoggedUser['Class']>=$MinClass)?true:false; +} + +// TODO: make stricter, e.g. on all whitespace characters or Unicode normalisation +function normalise_artist_name($ArtistName) { + // \u200e is ‎ + $ArtistName = trim($ArtistName); + $ArtistName = preg_replace('/^(\xE2\x80\x8E)+/', '', $ArtistName); + $ArtistName = preg_replace('/(\xE2\x80\x8E)+$/', '', $ArtistName); + return trim(preg_replace('/ +/', ' ', $ArtistName)); +} + +function get_artists($GroupIDs, $Escape = array()) { + global $Cache, $DB; + $Results = array(); + $DBs = array(); + foreach($GroupIDs as $GroupID) { + if(!is_number($GroupID)) { + continue; + } + $Artists = $Cache->get_value('groups_artists_'.$GroupID); + if(is_array($Artists)) { + $Results[$GroupID] = $Artists; + } else { + $DBs[] = $GroupID; + } + } + if(count($DBs) > 0) { + $IDs = implode(',', $DBs); + if(empty($IDs)) { + $IDs = "null"; + } + $DB->query("SELECT ta.GroupID, + ta.ArtistID, + aa.Name, + ta.Importance, + ta.AliasID + FROM torrents_artists AS ta + JOIN artists_alias AS aa ON ta.AliasID = aa.AliasID + WHERE ta.GroupID IN ($IDs) + ORDER BY ta.GroupID ASC, + ta.Importance ASC, + aa.Name ASC;"); + while(list($GroupID,$ArtistID,$ArtistName,$ArtistImportance,$AliasID) = $DB->next_record(MYSQLI_BOTH, false)) { + $Results[$GroupID][$ArtistImportance][] = array('id' => $ArtistID, 'name' => $ArtistName, 'aliasid' => $AliasID); + $New[$GroupID][$ArtistImportance][] = array('id' => $ArtistID, 'name' => $ArtistName, 'aliasid' => $AliasID); + } + foreach($DBs as $GroupID) { + if(isset($New[$GroupID])) { + $Cache->cache_value('groups_artists_'.$GroupID, $New[$GroupID]); + } + else { + $Cache->cache_value('groups_artists_'.$GroupID, array()); + } + } + $Missing = array_diff($GroupIDs, array_keys($Results)); + if(!empty($Missing)) { + $Results += array_fill_keys($Missing, array()); + } + } + return $Results; +} + +/** + * Convenience class for when you just need one group + * @param $GroupID + * @return unknown_type + */ +function get_artist($GroupID) { + $Results = get_artists(array($GroupID)); + return $Results[$GroupID]; +} + +function display_artists($Artists, $MakeLink = true, $IncludeHyphen = true, $Escape = true) { + if(!empty($Artists)) { + $ampersand = ($Escape) ? ' & ' : ' & '; + $link = ''; + + $MainArtists = $Artists[1]; + $Guests = $Artists[2]; + $Composers = $Artists[4]; + $Conductors = $Artists[5]; + $DJs = $Artists[6]; + + if ((count($MainArtists) + count($Conductors) + count($DJs) == 0) && (count($Composers) == 0)) { + return ''; + } + + // Various Composers is not needed and is ugly and should die + switch(count($Composers)) { + case 0: + break; + case 1: + $link .= display_artist($Composers[0], $MakeLink, $Escape); + break; + case 2: + $link .= display_artist($Composers[0], $MakeLink, $Escape).$ampersand.display_artist($Composers[1], $MakeLink, $Escape); + break; + } + + if ((count($Composers) > 0) && (count($Composers) < 3) && (count($MainArtists) > 0)) { + $link .= ' performed by '; + } + + $ComposerStr .= $link; + + switch(count($MainArtists)) { + case 0: + break; + case 1: + $link .= display_artist($MainArtists[0], $MakeLink, $Escape); + break; + case 2: + $link .= display_artist($MainArtists[0], $MakeLink, $Escape).$ampersand.display_artist($MainArtists[1], $MakeLink, $Escape); + break; + default: + $link .= 'Various Artists'; + } + + /*if(!empty($Guests) && (count($MainArtists) + count($Composers) > 0) && (count($MainArtists) + count($Composers) + count($Conductors) < 3)) { + switch(count($Guests)) { + case 1: + $link .= ' with '.display_artist($Guests[0], $MakeLink, $Escape); + break; + case 2: + $link .= ' with '.display_artist($Guests[0], $MakeLink, $Escape).$ampersand.display_artist($Guests[1], $MakeLink, $Escape); + break; + } + }*/ + + if ((count($Conductors) > 0) && (count($MainArtists) + count($Composers) > 0) && (count($Composers) < 3 || count($MainArtists) > 0)) { + $link .= ' under '; + } + switch(count($Conductors)) { + case 0: + break; + case 1: + $link .= display_artist($Conductors[0], $MakeLink, $Escape); + break; + case 2: + $link .= display_artist($Conductors[0], $MakeLink, $Escape).$ampersand.display_artist($Conductors[1], $MakeLink, $Escape); + break; + default: + $link .= ' Various Conductors'; + } + + if ((count($Composers) > 0) && (count($MainArtists) + count($Conductors) > 3) && (count($MainArtists) > 1) && (count($Conductors) > 1)) { + $link = $ComposerStr . 'Various Artists'; + } elseif ((count($Composers) > 2) && (count($MainArtists) + count($Conductors) == 0)) { + $link = 'Various Composers'; + } + + // DJs override everything else + switch(count($DJs)) { + case 0: + break; + case 1: + $link = display_artist($DJs[0], $MakeLink, $Escape); + break; + case 2: + $link = display_artist($DJs[0], $MakeLink, $Escape).$ampersand.display_artist($DJs[1], $MakeLink, $Escape); + break; + default : + $link = 'Various DJs'; + } + + return $link.($IncludeHyphen?' - ':''); + } else { + return ''; + } +} + +function display_artist($Artist, $MakeLink = true, $Escape = true) { + if ($MakeLink && !$Escape) { + error('Invalid parameters to display_artist()'); + } elseif ($MakeLink) { + return ''.display_str($Artist['name']).''; + } elseif ($Escape) { + return display_str($Artist['name']); + } else { + return $Artist['name']; + } +} + +// Function to get data and torrents for an array of GroupIDs. +// In places where the output from this is merged with sphinx filters, it will be in a different order. +function get_groups($GroupIDs, $Return = true, $GetArtists = true, $Torrents = true) { + global $DB, $Cache; + + $Found = array_flip($GroupIDs); + $NotFound = array_flip($GroupIDs); + $Key = $Torrents ? 'torrent_group_' : 'torrent_group_light_'; + + foreach($GroupIDs as $GroupID) { + $Data = $Cache->get_value($Key.$GroupID); + if(!empty($Data) && (@$Data['ver'] >= 4)) { + unset($NotFound[$GroupID]); + $Found[$GroupID] = $Data['d']; + } + } + + $IDs = implode(',',array_flip($NotFound)); + + /* + Changing any of these attributes returned will cause very large, very dramatic site-wide chaos. + Do not change what is returned or the order thereof without updating: + torrents, artists, collages, bookmarks, better, the front page, + and anywhere else the get_groups function is used. + */ + + if(count($NotFound)>0) { + $DB->query("SELECT g.ID, g.Name, g.Year, g.RecordLabel, g.CatalogueNumber, g.TagList, g.ReleaseType, g.VanityHouse FROM torrents_group AS g WHERE g.ID IN ($IDs)"); + + while($Group = $DB->next_record(MYSQLI_ASSOC, true)) { + unset($NotFound[$Group['ID']]); + $Found[$Group['ID']] = $Group; + $Found[$Group['ID']]['Torrents'] = array(); + $Found[$Group['ID']]['Artists'] = array(); + } + + if ($Torrents) { + $DB->query("SELECT + ID, GroupID, Media, Format, Encoding, RemasterYear, Remastered, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber, Scene, HasLog, HasCue, LogScore, FileCount, FreeTorrent, Size, Leechers, Seeders, Snatched, Time, ID AS HasFile + FROM torrents AS t WHERE GroupID IN($IDs) ORDER BY GroupID, Remastered, (RemasterYear <> 0) DESC, RemasterYear, RemasterTitle, RemasterRecordLabel, RemasterCatalogueNumber, Media, Format, Encoding, ID"); + while($Torrent = $DB->next_record(MYSQLI_ASSOC, true)) { + $Found[$Torrent['GroupID']]['Torrents'][$Torrent['ID']] = $Torrent; + + $Cache->cache_value('torrent_group_'.$Torrent['GroupID'], array('ver'=>4, 'd'=>$Found[$Torrent['GroupID']]), 0); + $Cache->cache_value('torrent_group_light_'.$Torrent['GroupID'], array('ver'=>4, 'd'=>$Found[$Torrent['GroupID']]), 0); + } + } else { + foreach ($Found as $Group) { + $Cache->cache_value('torrent_group_light_'.$Group['ID'], array('ver'=>4, 'd'=>$Found[$Group['ID']]), 0); + } + } + } + if($GetArtists) { + $Artists = get_artists($GroupIDs); + } else { + $Artists = array(); + } + + if($Return) { // If we're interested in the data, and not just caching it + foreach($Artists as $GroupID=>$Data) { + if(array_key_exists(1, $Data) || array_key_exists(4, $Data) || array_key_exists(6, $Data)) { + $Found[$GroupID]['Artists']=$Data[1]; // Only use main artists (legacy) + $Found[$GroupID]['ExtendedArtists'][1]=$Data[1]; + $Found[$GroupID]['ExtendedArtists'][2]=$Data[2]; + $Found[$GroupID]['ExtendedArtists'][3]=$Data[3]; + $Found[$GroupID]['ExtendedArtists'][4]=$Data[4]; + $Found[$GroupID]['ExtendedArtists'][5]=$Data[5]; + $Found[$GroupID]['ExtendedArtists'][6]=$Data[6]; + } + else { + $Found[$GroupID]['ExtendedArtists'] = false; + } + } + + $Matches = array('matches'=>$Found, 'notfound'=>array_flip($NotFound)); + + return $Matches; + } +} + +//Function to get data from an array of $RequestIDs. +//In places where the output from this is merged with sphinx filters, it will be in a different order. +function get_requests($RequestIDs, $Return = true) { + global $DB, $Cache; + + $Found = array_flip($RequestIDs); + $NotFound = array_flip($RequestIDs); + + foreach($RequestIDs as $RequestID) { + $Data = $Cache->get_value('request_'.$RequestID); + if(!empty($Data)) { + unset($NotFound[$RequestID]); + $Found[$RequestID] = $Data; + } + } + + $IDs = implode(',',array_flip($NotFound)); + + /* + Don't change without ensuring you change everything else that uses get_requests() + */ + + if(count($NotFound) > 0) { + $DB->query("SELECT + r.ID AS ID, + r.UserID, + u.Username, + r.TimeAdded, + r.LastVote, + r.CategoryID, + r.Title, + r.Year, + r.Image, + r.Description, + r.CatalogueNumber, + r.RecordLabel, + r.ReleaseType, + r.BitrateList, + r.FormatList, + r.MediaList, + r.LogCue, + r.FillerID, + filler.Username, + r.TorrentID, + r.TimeFilled, + r.GroupID + FROM requests AS r + LEFT JOIN users_main AS u ON u.ID=r.UserID + LEFT JOIN users_main AS filler ON filler.ID=FillerID AND FillerID!=0 + WHERE r.ID IN (".$IDs.") + ORDER BY ID"); + + $Requests = $DB->to_array(); + foreach($Requests as $Request) { + unset($NotFound[$Request['ID']]); + $Request['Tags'] = get_request_tags($Request['ID']); + $Found[$Request['ID']] = $Request; + $Cache->cache_value('request_'.$Request['ID'], $Request, 0); + } + } + + if($Return) { // If we're interested in the data, and not just caching it + $Matches = array('matches'=>$Found, 'notfound'=>array_flip($NotFound)); + return $Matches; + } +} + +function update_sphinx_requests($RequestID) { + global $DB, $Cache; + + $DB->query("REPLACE INTO sphinx_requests_delta ( + ID, UserID, TimeAdded, LastVote, CategoryID, Title, + Year, ReleaseType, CatalogueNumber, BitrateList, + FormatList, MediaList, LogCue, FillerID, TorrentID, + TimeFilled, Visible, Votes, Bounty) + SELECT + ID, r.UserID, UNIX_TIMESTAMP(TimeAdded) AS TimeAdded, + UNIX_TIMESTAMP(LastVote) AS LastVote, CategoryID, + Title, Year, ReleaseType, CatalogueNumber, BitrateList, + FormatList, MediaList, LogCue, FillerID, TorrentID, + UNIX_TIMESTAMP(TimeFilled) AS TimeFilled, Visible, + COUNT(rv.UserID) AS Votes, SUM(rv.Bounty) >> 10 AS Bounty + FROM requests AS r LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID + wHERE ID = ".$RequestID." + GROUP BY r.ID"); + + $DB->query("UPDATE sphinx_requests_delta + SET ArtistList = (SELECT + GROUP_CONCAT(aa.Name SEPARATOR ' ') + FROM requests_artists AS ra + JOIN artists_alias AS aa ON aa.AliasID=ra.AliasID + WHERE ra.RequestID = ".$RequestID." + GROUP BY NULL) + WHERE ID = ".$RequestID); + + $Cache->delete_value('requests_'.$RequestID); +} + +function get_tags($TagNames) { + global $Cache, $DB; + $TagIDs = array(); + foreach($TagNames as $Index => $TagName) { + $Tag = $Cache->get_value('tag_id_'.$TagName); + if(is_array($Tag)) { + unset($TagNames[$Index]); + $TagIDs[$Tag['ID']] = $Tag['Name']; + } + } + if(count($TagNames) > 0) { + $DB->query("SELECT ID, Name FROM tags WHERE Name IN ('".implode("', '", $TagNames)."')"); + $SQLTagIDs = $DB->to_array(); + foreach($SQLTagIDs as $Tag) { + $TagIDs[$Tag['ID']] = $Tag['Name']; + $Cache->cache_value('tag_id_'.$Tag['Name'], $Tag, 0); + } + } + + return($TagIDs); +} + +function torrent_info($Data) { + $Info = array(); + if(!empty($Data['Format'])) { $Info[]=$Data['Format']; } + if(!empty($Data['Encoding'])) { $Info[]=$Data['Encoding']; } + if(!empty($Data['HasLog'])) { + $Str = 'Log'; + if(!empty($Data['LogScore'])) { + $Str.=' ('.$Data['LogScore'].'%)'; + } + $Info[]=$Str; + } + if(!empty($Data['HasCue'])) { $Info[]='Cue'; } + if(!empty($Data['Scene'])) { $Info[]='Scene'; } + if($Data['FreeTorrent'] == '1') { $Info[]='Freeleech!'; } + if($Data['FreeTorrent'] == '2') { $Info[]='Neutral Leech!'; } + if($Data['PersonalFL'] == 1) { $Info[]='Personal Freeleech!'; } + return implode(' / ', $Info); +} + +// Echo data sent in a form, typically a text area +function form($Index, $Return = false) { + if(!empty($_GET[$Index])) { + if($Return) { + return display_str($_GET[$Index]); + } else { + echo display_str($_GET[$Index]); + } + } +} + +// Check/select tickboxes and + + + value="Torrents" type="text" name="groupname" size="17" + + value="Torrents" type="text" name="searchstr" size="17" + + /> + + +
  5. + +
    + + + +
    +
  6. +
  7. + +
    + +
    +
  8. +
  9. + +
    + + +
    +
  10. + +
  11. + +
    + +
    +
  12. +
  13. + +
    + + +
    +
  14. + + + + +
    diff --git a/design/publicfooter.php b/design/publicfooter.php new file mode 100644 index 00000000..7927ff85 --- /dev/null +++ b/design/publicfooter.php @@ -0,0 +1,8 @@ + + + + + + diff --git a/design/publicheader.php b/design/publicheader.php new file mode 100644 index 00000000..9bf84aac --- /dev/null +++ b/design/publicheader.php @@ -0,0 +1,48 @@ + + + + + <?=display_str($PageTitle)?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $Torrent) { + $NumTorrents++; + + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + $Torrent['Seeders'] = (int)$Torrent['Seeders']; + $Torrent['Leechers'] = (int)$Torrent['Leechers']; + $Torrent['Snatched'] = (int)$Torrent['Snatched']; + + $NumSeeders+=$Torrent['Seeders']; + $NumLeechers+=$Torrent['Leechers']; + $NumSnatches+=$Torrent['Snatched']; + } + foreach ($Torrents as $Torrent) { + $InnerTorrents[] = array( + 'id' => (int) $Torrent['ID'], + 'groupId' => (int) $Torrent['GroupID'], + 'media' => $Torrent['Media'], + 'format' => $Torrent['Format'], + 'encoding' => $Torrent['Encoding'], + 'remasterYear' => (int) $Torrent['RemasterYear'], + 'remastered' => $Torrent['Remastered'] == 1, + 'remasterTitle' => $Torrent['RemasterTitle'], + 'remasterRecordLabel' => $Torrent['RemasterRecordLabel'], + 'scene' => $Torrent['Scene'] == 1, + 'hasLog' => $Torrent['HasLog'] == 1, + 'hasCue' => $Torrent['HasCue'] == 1, + 'logScore' => (int) $Torrent['LogScore'], + 'fileCount' => (int) $Torrent['FileCount'], + 'freeTorrent' => $Torrent['FreeTorrent'] == 1, + 'size' => (int) $Torrent['Size'], + 'leechers' => (int) $Torrent['Leechers'], + 'seeders' => (int) $Torrent['Seeders'], + 'snatched' => (int) $Torrent['Snatched'], + 'time' => $Torrent['Time'], + 'hasFile' => (int) $Torrent['HasFile'] + ); + } + $JsonTorrents[] = array( + 'groupId' => (int) $GroupID, + 'groupName' => $GroupName, + 'groupYear' => (int) $GroupYear, + 'groupRecordLabel' => $GroupRecordLabel, + 'groupCatalogueNumber' => $GroupCatalogueNumber, + 'tags' => $TagList, + 'releaseType' => (int) $ReleaseType, + 'groupVanityHouse' => $GroupVanityHouse == 1, + 'hasBookmarked' => $hasBookmarked = has_bookmarked('torrent', $GroupID), + 'torrent' => $InnerTorrents + ); +} + +$TorrentDisplayList = ob_get_clean(); + +$JsonSimilar = array(); +if(empty($SimilarArray)) { + $DB->query(" + SELECT + s2.ArtistID, + a.Name, + ass.Score, + ass.SimilarID + FROM artists_similar AS s1 + JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID + JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID + JOIN artists_group AS a ON a.ArtistID=s2.ArtistID + WHERE s1.ArtistID='$ArtistID' + ORDER BY ass.Score DESC + LIMIT 30 + "); + $SimilarArray = $DB->to_array(); + foreach ($SimilarArray as $Similar) { + $JsonSimilar[] = array( + 'artistId' => (int) $Similar['ArtistID'], + 'name' => $Similar['Name'], + 'score' => (int) $Similar['Score'], + 'similarId' => (int) $Similar['SimilarID'] + ); + } + $NumSimilar = count($SimilarArray); +} + +$JsonRequests = array(); +foreach ($Requests as $Request) { + list($RequestID, $CategoryID, $Title, $Year, $TimeAdded, $Votes, $Bounty) = $Request; + $JsonRequests[] = array( + 'requestId' => (int) $RequestID, + 'categoryId' => (int) $CategoryID, + 'title' => $Title, + 'year' => (int) $Year, + 'timeAdded' => $TimeAdded, + 'votes' => (int) $Votes, + 'bounty' => (int) $Bounty + ); +} + +//notifications disabled by default +$notificationsEnabled = False; +if (check_perms('site_torrents_notify')) { + if (($Notify = $Cache->get_value('notify_artists_'.$LoggedUser['ID'])) === false) { + $DB->query("SELECT ID, Artists FROM users_notify_filters WHERE UserID='$LoggedUser[ID]' AND Label='Artist notifications' LIMIT 1"); + $Notify = $DB->next_record(MYSQLI_ASSOC, false); + $Cache->cache_value('notify_artists_'.$LoggedUser['ID'], $Notify, 0); + } + if (stripos($Notify['Artists'], '|'.$Name.'|') === false) { + $notificationsEnabled = False; + } else { + $notificationsEnabled = True; + } +} + + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'id' => (int) $ArtistID, + 'name' => $Name, + 'notificationsEnabled' => $notificationsEnabled, + 'hasBookmarked' => has_bookmarked('artist', $ArtistID), + 'image' => $Image, + 'body' => $Text->full_format($Body), + 'vanityHouse' => $VanityHouseArtist == 1, + 'tags' => array_values($Tags), + 'similarArtists' => $JsonSimilar, + 'statistics' => array( + 'numGroups' => $NumGroups, + 'numTorrents' => $NumTorrents, + 'numSeeders' => $NumSeeders, + 'numLeechers' => $NumLeechers, + 'numSnatches' => $NumSnatches + ), + 'torrentgroup' => $JsonTorrents, + 'requests' => $JsonRequests + ) + ) + ) +?> diff --git a/sections/ajax/better/index.php b/sections/ajax/better/index.php new file mode 100644 index 00000000..ca48fcf9 --- /dev/null +++ b/sections/ajax/better/index.php @@ -0,0 +1,38 @@ + 'failure')); + break; + } +} else { + print json_encode(array('status' => 'failure')); +} +?> diff --git a/sections/ajax/better/single.php b/sections/ajax/better/single.php new file mode 100644 index 00000000..b0a3a494 --- /dev/null +++ b/sections/ajax/better/single.php @@ -0,0 +1,47 @@ +get_value('better_single_groupids')) === false) { + $DB->query("SELECT t.ID AS TorrentID, + t.GroupID AS GroupID + FROM xbt_files_users AS x + JOIN torrents AS t ON t.ID=x.fid + WHERE t.Format='FLAC' + GROUP BY x.fid + HAVING COUNT(x.uid) = 1 + ORDER BY t.LogScore DESC, t.Time ASC LIMIT 30"); + + $GroupIDs = $DB->to_array('GroupID'); + $Cache->cache_value('better_single_groupids', $GroupIDs, 30*60); +} + +$Results = get_groups(array_keys($GroupIDs)); + +$Results = $Results['matches']; + +$JsonResults = array(); +foreach ($Results as $GroupID=>$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Group); + $FlacID = $GroupIDs[$GroupID]['TorrentID']; + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + + $JsonResults[] = array( + 'torrentId' => (int) $FlacID, + 'groupId' => (int) $GroupID, + 'artist' => $Artists, + 'groupName' => $GroupName, + 'groupYear' => (int) $GroupYear, + 'downloadUrl' => 'torrents.php?action=download&id='.$FlacID.'&authkey='.$LoggedUser['AuthKey'].'&torrent_pass='.$LoggedUser['torrent_pass'] + ); +} + +print json_encode( + array( + 'status' => 'success', + 'response' => $JsonResults + ) +); diff --git a/sections/ajax/better/transcode.php b/sections/ajax/better/transcode.php new file mode 100644 index 00000000..9fc67bd2 --- /dev/null +++ b/sections/ajax/better/transcode.php @@ -0,0 +1,111 @@ + 3) { error(0); } + +$Options = array('v0','v2','320'); + +if ($_GET['type'] == 3) { + $List = "!(v0 | v2 | 320)"; +} else { + $List = '!'.$Options[$_GET['type']]; + if($_GET['type'] == 0) { + $_GET['type'] = '0'; + } else { + $_GET['type'] = display_str($_GET['type']); + } +} + +$Query = '@format FLAC @encoding '.$List; + +if(!empty($_GET['search'])) { + $Query.=' @(groupname,artistname,yearfulltext) '.$SS->EscapeString($_GET['search']); +} + +$SS->SetFilter('logscore', array(100)); +$SS->SetSortMode(SPH_SORT_EXTENDED, "@random"); +$SS->limit(0, TORRENTS_PER_PAGE); + +$SS->set_index(SPHINX_INDEX.' delta'); + +$Results = $SS->search($Query, '', 0, array(), '', ''); + +if(count($Results) == 0) { error('No results found!'); } +/* +// If some were fetched from memcached, get their artists +if(!empty($Results['matches'])) { // Fetch the artists for groups + $GroupIDs = array_keys($Results['matches']); + $Artists = get_artists($GroupIDs); + foreach($Artists as $GroupID=>$Data) { + if(!empty($Data[1])) { + $Results['matches'][$GroupID]['Artists']=$Data[1]; // Only use main artists + } + ksort($Results['matches'][$GroupID]); + } +} +*/ + // These ones were not found in the cache, run SQL +if(!empty($Results['notfound'])) { + $SQLResults = get_groups($Results['notfound']); + + if(is_array($SQLResults['notfound'])) { // Something wasn't found in the db, remove it from results + reset($SQLResults['notfound']); + foreach($SQLResults['notfound'] as $ID) { + unset($SQLResults['matches'][$ID]); + unset($Results['matches'][$ID]); + } + } + + // Merge SQL results with memcached results + foreach($SQLResults['matches'] as $ID=>$SQLResult) { + $Results['matches'][$ID] = array_merge($Results['matches'][$ID], $SQLResult); + ksort($Results['matches'][$ID]); + } +} + +$Results = $Results['matches']; + +$JsonResults = array(); +foreach($Results as $GroupID=>$Data) { +$Debug->log_var($Data); + list($Artists, $GroupCatalogueNumber, $ExtendedArtists, $GroupID2, $GroupName, $GroupRecordLabel, $ReleaseType, $TagList, $Torrents, $GroupVanityHouse, $GroupYear, $CategoryID, $FreeTorrent, $HasCue, $HasLog, $TotalLeechers, $LogScore, $ReleaseType, $ReleaseType, $TotalSeeders, $MaxSize, $TotalSnatched, $GroupTime) = array_values($Data); + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + + $MissingEncodings = array('V0 (VBR)'=>1, 'V2 (VBR)'=>1, '320'=>1); + $FlacID = 0; + + foreach($Torrents as $Torrent) { + if(!empty($MissingEncodings[$Torrent['Encoding']])) { + $MissingEncodings[$Torrent['Encoding']] = 0; + } elseif($Torrent['Format'] == 'FLAC' && $FlacID == 0) { + $FlacID = $Torrent['ID']; + } + } + + if($_GET['type'] == '3' && in_array(0, $MissingEncodings)) { + continue; + } + + $JsonResults[] = array( + 'torrentId' => (int) $TorrentID, + 'groupId' => (int) $GroupID, + 'artist' => $DisplayName, + 'groupName' => $GroupName, + 'groupYear' => (int) $GroupYear, + 'missingV2' => $MissingEncodings['V2 (VBR)'] == 0, + 'missingV0' => $MissingEncodings['V0 (VBR)'] == 0, + 'missing320' => $MissingEncodings['320'] == 0, + 'downloadUrl' => 'torrents.php?action=download&id='.$FlacID.'&authkey='.$LoggedUser['AuthKey'].'&torrent_pass='.$LoggedUser['torrent_pass'] + ); +} + +print json_encode( + array( + 'status' => 'success', + 'response' => $JsonResults + ) +); diff --git a/sections/ajax/bookmarks.php b/sections/ajax/bookmarks.php new file mode 100644 index 00000000..d9f1321d --- /dev/null +++ b/sections/ajax/bookmarks.php @@ -0,0 +1,246 @@ +query("SELECT Username FROM users_main WHERE ID='$UserID'"); + list($Username) = $DB->next_record(); +} else { + $UserID = $LoggedUser['ID']; +} + +$Sneaky = ($UserID != $LoggedUser['ID']); + +$Data = $Cache->get_value('bookmarks_torrent_'.$UserID.'_full'); + +if($Data) { + $Data = unserialize($Data); + list($K, list($TorrentList, $CollageDataList)) = each($Data); +} else { + // Build the data for the collage and the torrent list + $DB->query("SELECT + bt.GroupID, + tg.WikiImage, + tg.CategoryID, + bt.Time + FROM bookmarks_torrents AS bt + JOIN torrents_group AS tg ON tg.ID=bt.GroupID + WHERE bt.UserID='$UserID' + ORDER BY bt.Time"); + + $GroupIDs = $DB->collect('GroupID'); + $CollageDataList=$DB->to_array('GroupID', MYSQLI_ASSOC); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} + +$Title = ($Sneaky)?"$Username's bookmarked torrents":'Your bookmarked torrents'; + + +// Loop through the result set, building up $Collage and $TorrentTable +// Then we print them. +$Collage = array(); +$TorrentTable = ''; + +$NumGroups = 0; +$Artists = array(); +$Tags = array(); + +foreach ($TorrentList as $GroupID=>$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists) = array_values($Group); + list($GroupID2, $Image, $GroupCategoryID, $AddedTime) = array_values($CollageDataList[$GroupID]); + + // Handle stats and stuff + $NumGroups++; + + if($GroupArtists) { + foreach($GroupArtists as $Artist) { + if(!isset($Artists[$Artist['id']])) { + $Artists[$Artist['id']] = array('name'=>$Artist['name'], 'count'=>1); + } else { + $Artists[$Artist['id']]['count']++; + } + } + } + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + $TorrentTags[]=''.$Tag.''; + } + $PrimaryTag = $TagList[0]; + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags='
    '.$TorrentTags.'
    '; + + $DisplayName = ''; + if(count($GroupArtists)>0) { + $DisplayName = display_artists(array('1'=>$GroupArtists)); + } + $DisplayName .= ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + + // Start an output buffer, so we can store this output in $TorrentTable + ob_start(); + if(count($Torrents)>1 || $GroupCategoryID==1) { + // Grouped torrents + $ShowGroups = !(!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1); + $LastRemasterYear = '-'; + $LastRemasterTitle = ''; + $LastRemasterRecordLabel = ''; + $LastRemasterCatalogueNumber = ''; + $LastMedia = ''; + + $EditionID = 0; + unset($FirstUnknown); + + foreach ($Torrents as $TorrentID => $Torrent) { + + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) { + + $EditionID++; + if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) { + + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + + } else { + $AddExtra = " / "; + if (!$Torrent['Remastered']) { + $MasterName = "Original Release"; + if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; } + if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; } + } else { + $MasterName = "Unknown Release(s)"; + } + $MasterName .= $AddExtra.display_str($Torrent['Media']); + } + } + $LastRemasterTitle = $Torrent['RemasterTitle']; + $LastRemasterYear = $Torrent['RemasterYear']; + $LastRemasterRecordLabel = $Torrent['RemasterRecordLabel']; + $LastRemasterCatalogueNumber = $Torrent['RemasterCatalogueNumber']; + $LastMedia = $Torrent['Media']; + } + } else { + // Viewing a type that does not require grouping + + list($TorrentID, $Torrent) = each($Torrents); + + $DisplayName = ''.$GroupName.''; + + if(!empty($Torrent['FreeTorrent'])) { + $DisplayName .=' Freeleech!'; + } + } + $TorrentTable.=ob_get_clean(); + + // Album art + + ob_start(); + + $DisplayName = ''; + if(!empty($GroupArtists)) { + $DisplayName.= display_artists(array('1'=>$GroupArtists), false); + } + $DisplayName .= $GroupName; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + $Collage[]=ob_get_clean(); + +} + +uasort($Tags, 'compare'); +$i = 0; +foreach ($Tags as $TagName => $Tag) { + $i++; + if($i>5) { break; } +uasort($Artists, 'compare'); +$i = 0; +foreach ($Artists as $ID => $Artist) { + $i++; + if($i>10) { break; } +} +} + +$JsonBookmarks = array(); +foreach ($TorrentList as $Torrent) { + $JsonTorrents = array(); + foreach ($Torrent['Torrents'] as $GroupTorrents) { + $JsonTorrents[] = array( + 'id' => (int) $GroupTorrents['ID'], + 'groupId' => (int) $GroupTorrents['GroupID'], + 'media' => $GroupTorrents['Media'], + 'format' => $GroupTorrents['Format'], + 'encoding' => $GroupTorrents['Encoding'], + 'remasterYear' => (int) $GroupTorrents['RemasterYear'], + 'remastered' => $GroupTorrents['Remastered'] == 1, + 'remasterTitle' => $GroupTorrents['RemasterTitle'], + 'remasterRecordLabel' => $GroupTorrents['RemasterRecordLabel'], + 'remasterCatalogueNumber' => $GroupTorrents['RemasterCatalogueNumber'], + 'scene' => $GroupTorrents['Scene'] == 1, + 'hasLog' => $GroupTorrents['HasLog'] == 1, + 'hasCue' => $GroupTorrents['HasCue'] == 1, + 'logScore' => (float) $GroupTorrents['LogScore'], + 'fileCount' => (int) $GroupTorrents['FileCount'], + 'freeTorrent' => $GroupTorrents['FreeTorrent'] == 1, + 'size' => (float) $GroupTorrents['Size'], + 'leechers' => (int) $GroupTorrents['Leechers'], + 'seeders' => (int) $GroupTorrents['Seeders'], + 'snatched' => (int) $GroupTorrents['Snatched'], + 'time' => $GroupTorrents['Time'], + 'hasFile' => (int) $GroupTorrents['HasFile'] + ); + } + $JsonBookmarks[] = array( + 'id' => (int) $Torrent['ID'], + 'name' => $Torrent['Name'], + 'year' => (int) $Torrent['Year'], + 'recordLabel' => $Torrent['RecordLabel'], + 'catalogueNumber' => $Torrent['CatalogueNumber'], + 'tagList' => $Torrent['TagList'], + 'releaseType' => $Torrent['ReleaseType'], + 'vanityHouse' => $Torrent['VanityHouse'] == 1, + 'torrents' => $JsonTorrents + ); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'bookmarks' => $JsonBookmarks + ) + ) + ); +?> diff --git a/sections/ajax/bookmarks/artists.php b/sections/ajax/bookmarks/artists.php new file mode 100644 index 00000000..c8b6efad --- /dev/null +++ b/sections/ajax/bookmarks/artists.php @@ -0,0 +1,60 @@ + 'failure' + ) + ); + die(); + } + $UserID = $_GET['userid']; + $Sneaky = ($UserID != $LoggedUser['ID']); + if(!is_number($UserID)) { + print + json_encode( + array( + 'status' => 'failure' + ) + ); + die(); + } + $DB->query("SELECT Username FROM users_main WHERE ID='$UserID'"); + list($Username) = $DB->next_record(); +} else { + $UserID = $LoggedUser['ID']; +} + +$Sneaky = ($UserID != $LoggedUser['ID']); + +//$ArtistList = all_bookmarks('artist', $UserID); + +$DB->query('SELECT ag.ArtistID, ag.Name + FROM bookmarks_artists AS ba + INNER JOIN artists_group AS ag ON ba.ArtistID = ag.ArtistID + WHERE ba.UserID = '.$UserID); + +$ArtistList = $DB->to_array(); + +$JsonArtists = array(); +foreach($ArtistList as $Artist) { + list($ArtistID, $Name) = $Artist; + $JsonArtists[] = array( + 'artistId' => (int) $ArtistID, + 'artistName' => $Name + ); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'artists' => $JsonArtists + ) + ) + ); + +?> diff --git a/sections/ajax/bookmarks/index.php b/sections/ajax/bookmarks/index.php new file mode 100644 index 00000000..39d3c49d --- /dev/null +++ b/sections/ajax/bookmarks/index.php @@ -0,0 +1,35 @@ + 'failure' + ) + ); + die(); +} + +?> diff --git a/sections/ajax/bookmarks/torrents.php b/sections/ajax/bookmarks/torrents.php new file mode 100644 index 00000000..d9f1321d --- /dev/null +++ b/sections/ajax/bookmarks/torrents.php @@ -0,0 +1,246 @@ +query("SELECT Username FROM users_main WHERE ID='$UserID'"); + list($Username) = $DB->next_record(); +} else { + $UserID = $LoggedUser['ID']; +} + +$Sneaky = ($UserID != $LoggedUser['ID']); + +$Data = $Cache->get_value('bookmarks_torrent_'.$UserID.'_full'); + +if($Data) { + $Data = unserialize($Data); + list($K, list($TorrentList, $CollageDataList)) = each($Data); +} else { + // Build the data for the collage and the torrent list + $DB->query("SELECT + bt.GroupID, + tg.WikiImage, + tg.CategoryID, + bt.Time + FROM bookmarks_torrents AS bt + JOIN torrents_group AS tg ON tg.ID=bt.GroupID + WHERE bt.UserID='$UserID' + ORDER BY bt.Time"); + + $GroupIDs = $DB->collect('GroupID'); + $CollageDataList=$DB->to_array('GroupID', MYSQLI_ASSOC); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} + +$Title = ($Sneaky)?"$Username's bookmarked torrents":'Your bookmarked torrents'; + + +// Loop through the result set, building up $Collage and $TorrentTable +// Then we print them. +$Collage = array(); +$TorrentTable = ''; + +$NumGroups = 0; +$Artists = array(); +$Tags = array(); + +foreach ($TorrentList as $GroupID=>$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists) = array_values($Group); + list($GroupID2, $Image, $GroupCategoryID, $AddedTime) = array_values($CollageDataList[$GroupID]); + + // Handle stats and stuff + $NumGroups++; + + if($GroupArtists) { + foreach($GroupArtists as $Artist) { + if(!isset($Artists[$Artist['id']])) { + $Artists[$Artist['id']] = array('name'=>$Artist['name'], 'count'=>1); + } else { + $Artists[$Artist['id']]['count']++; + } + } + } + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + $TorrentTags[]=''.$Tag.''; + } + $PrimaryTag = $TagList[0]; + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags='
    '.$TorrentTags.'
    '; + + $DisplayName = ''; + if(count($GroupArtists)>0) { + $DisplayName = display_artists(array('1'=>$GroupArtists)); + } + $DisplayName .= ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + + // Start an output buffer, so we can store this output in $TorrentTable + ob_start(); + if(count($Torrents)>1 || $GroupCategoryID==1) { + // Grouped torrents + $ShowGroups = !(!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1); + $LastRemasterYear = '-'; + $LastRemasterTitle = ''; + $LastRemasterRecordLabel = ''; + $LastRemasterCatalogueNumber = ''; + $LastMedia = ''; + + $EditionID = 0; + unset($FirstUnknown); + + foreach ($Torrents as $TorrentID => $Torrent) { + + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) { + + $EditionID++; + if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) { + + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + + } else { + $AddExtra = " / "; + if (!$Torrent['Remastered']) { + $MasterName = "Original Release"; + if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; } + if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; } + } else { + $MasterName = "Unknown Release(s)"; + } + $MasterName .= $AddExtra.display_str($Torrent['Media']); + } + } + $LastRemasterTitle = $Torrent['RemasterTitle']; + $LastRemasterYear = $Torrent['RemasterYear']; + $LastRemasterRecordLabel = $Torrent['RemasterRecordLabel']; + $LastRemasterCatalogueNumber = $Torrent['RemasterCatalogueNumber']; + $LastMedia = $Torrent['Media']; + } + } else { + // Viewing a type that does not require grouping + + list($TorrentID, $Torrent) = each($Torrents); + + $DisplayName = ''.$GroupName.''; + + if(!empty($Torrent['FreeTorrent'])) { + $DisplayName .=' Freeleech!'; + } + } + $TorrentTable.=ob_get_clean(); + + // Album art + + ob_start(); + + $DisplayName = ''; + if(!empty($GroupArtists)) { + $DisplayName.= display_artists(array('1'=>$GroupArtists), false); + } + $DisplayName .= $GroupName; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + $Collage[]=ob_get_clean(); + +} + +uasort($Tags, 'compare'); +$i = 0; +foreach ($Tags as $TagName => $Tag) { + $i++; + if($i>5) { break; } +uasort($Artists, 'compare'); +$i = 0; +foreach ($Artists as $ID => $Artist) { + $i++; + if($i>10) { break; } +} +} + +$JsonBookmarks = array(); +foreach ($TorrentList as $Torrent) { + $JsonTorrents = array(); + foreach ($Torrent['Torrents'] as $GroupTorrents) { + $JsonTorrents[] = array( + 'id' => (int) $GroupTorrents['ID'], + 'groupId' => (int) $GroupTorrents['GroupID'], + 'media' => $GroupTorrents['Media'], + 'format' => $GroupTorrents['Format'], + 'encoding' => $GroupTorrents['Encoding'], + 'remasterYear' => (int) $GroupTorrents['RemasterYear'], + 'remastered' => $GroupTorrents['Remastered'] == 1, + 'remasterTitle' => $GroupTorrents['RemasterTitle'], + 'remasterRecordLabel' => $GroupTorrents['RemasterRecordLabel'], + 'remasterCatalogueNumber' => $GroupTorrents['RemasterCatalogueNumber'], + 'scene' => $GroupTorrents['Scene'] == 1, + 'hasLog' => $GroupTorrents['HasLog'] == 1, + 'hasCue' => $GroupTorrents['HasCue'] == 1, + 'logScore' => (float) $GroupTorrents['LogScore'], + 'fileCount' => (int) $GroupTorrents['FileCount'], + 'freeTorrent' => $GroupTorrents['FreeTorrent'] == 1, + 'size' => (float) $GroupTorrents['Size'], + 'leechers' => (int) $GroupTorrents['Leechers'], + 'seeders' => (int) $GroupTorrents['Seeders'], + 'snatched' => (int) $GroupTorrents['Snatched'], + 'time' => $GroupTorrents['Time'], + 'hasFile' => (int) $GroupTorrents['HasFile'] + ); + } + $JsonBookmarks[] = array( + 'id' => (int) $Torrent['ID'], + 'name' => $Torrent['Name'], + 'year' => (int) $Torrent['Year'], + 'recordLabel' => $Torrent['RecordLabel'], + 'catalogueNumber' => $Torrent['CatalogueNumber'], + 'tagList' => $Torrent['TagList'], + 'releaseType' => $Torrent['ReleaseType'], + 'vanityHouse' => $Torrent['VanityHouse'] == 1, + 'torrents' => $JsonTorrents + ); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'bookmarks' => $JsonBookmarks + ) + ) + ); +?> diff --git a/sections/ajax/browse.php b/sections/ajax/browse.php new file mode 100644 index 00000000..f9cf8e55 --- /dev/null +++ b/sections/ajax/browse.php @@ -0,0 +1,597 @@ +get_value('users_tokens_'.$UserID); +if (empty($TokenTorrents)) { + $DB->query("SELECT TorrentID FROM users_freeleeches WHERE UserID=$UserID AND Expired=FALSE"); + $TokenTorrents = $DB->collect('TorrentID'); + $Cache->cache_value('users_tokens_'.$UserID, $TokenTorrents); +} + +// Setting default search options +if(!empty($_GET['setdefault'])) { + $UnsetList = array('page','setdefault'); + $UnsetRegexp = '/(&|^)('.implode('|',$UnsetList).')=.*?(&|$)/i'; + + $DB->query("SELECT SiteOptions FROM users_info WHERE UserID='".db_string($LoggedUser['ID'])."'"); + list($SiteOptions)=$DB->next_record(MYSQLI_NUM, false); + if(!empty($SiteOptions)) { + $SiteOptions = unserialize($SiteOptions); + } else { + $SiteOptions = array(); + } + $SiteOptions['DefaultSearch'] = preg_replace($UnsetRegexp,'',$_SERVER['QUERY_STRING']); + $DB->query("UPDATE users_info SET SiteOptions='".db_string(serialize($SiteOptions))."' WHERE UserID='".db_string($LoggedUser['ID'])."'"); + $Cache->begin_transaction('user_info_heavy_'.$UserID); + $Cache->update_row(false, array('DefaultSearch'=>$SiteOptions['DefaultSearch'])); + $Cache->commit_transaction(0); + +// Clearing default search options +} elseif(!empty($_GET['cleardefault'])) { + $DB->query("SELECT SiteOptions FROM users_info WHERE UserID='".db_string($LoggedUser['ID'])."'"); + list($SiteOptions)=$DB->next_record(MYSQLI_NUM, false); + $SiteOptions=unserialize($SiteOptions); + $SiteOptions['DefaultSearch']=''; + $DB->query("UPDATE users_info SET SiteOptions='".db_string(serialize($SiteOptions))."' WHERE UserID='".db_string($LoggedUser['ID'])."'"); + $Cache->begin_transaction('user_info_heavy_'.$UserID); + $Cache->update_row(false, array('DefaultSearch'=>'')); + $Cache->commit_transaction(0); + +// Use default search options +} elseif((empty($_SERVER['QUERY_STRING']) || (count($_GET) == 1 && isset($_GET['page']))) && !empty($LoggedUser['DefaultSearch'])) { + if(!empty($_GET['page'])) { + $Page = $_GET['page']; + parse_str($LoggedUser['DefaultSearch'],$_GET); + $_GET['page'] = $Page; + } else { + parse_str($LoggedUser['DefaultSearch'],$_GET); + } +} + +array_pop($Bitrates); // remove 'other' +$SearchBitrates = array_merge($Bitrates, array('v0','v1','v2','24bit')); + +foreach($SearchBitrates as $ID=>$Val) { + $SearchBitrates[$ID]=strtolower($Val); +} +foreach($Formats as $ID=>$Val) { + $SearchFormats[$ID]=strtolower($Val); +} + +$Queries = array(); + +//Simple search +if(!empty($_GET['searchstr'])) { + $Words = explode(' ',strtolower($_GET['searchstr'])); + $FilterBitrates = array_intersect($Words, $SearchBitrates); + if(count($FilterBitrates)>0) { + $Queries[]='@encoding '.implode(' ',$FilterBitrates); + } + + $FilterFormats = array_intersect($Words, $SearchFormats); + if(count($FilterFormats)>0) { + $Queries[]='@format '.implode(' ',$FilterFormats); + } + + if(in_array('100%', $Words)) { + $_GET['haslog'] = '100'; + unset($Words[array_search('100%',$Words)]); + } + + $Words = array_diff($Words, $FilterBitrates, $FilterFormats); + if(!empty($Words)) { + foreach($Words as $Key => &$Word) { + if($Word[0] == '!' && strlen($Word) >= 3 && count($Words) >= 2) { + if(strpos($Word,'!',1) === false) { + $Word = '!'.$SS->EscapeString(substr($Word,1)); + } else { + $Word = $SS->EscapeString($Word); + } + } elseif(strlen($Word) >= 2) { + $Word = $SS->EscapeString($Word); + } else { + unset($Words[$Key]); + } + } + unset($Word); + $Words = trim(implode(' ',$Words)); + if(!empty($Words)) { + $Queries[]='@(groupname,artistname,yearfulltext) '.$Words; + } + } +} + +if(!empty($_GET['taglist'])) { + $_GET['taglist'] = str_replace('.','_',$_GET['taglist']); + $TagList = explode(',',$_GET['taglist']); + $TagListEx = array(); + foreach($TagList as $Key => &$Tag) { + $Tag = trim($Tag); + if(strlen($Tag) >= 2) { + if($Tag[0] == '!' && strlen($Tag) >= 3) { + $TagListEx[] = '!'.$SS->EscapeString(substr($Tag,1)); + unset($TagList[$Key]); + } else { + $Tag = $SS->EscapeString($Tag); + } + } else { + unset($TagList[$Key]); + } + } + unset($Tag); +} + +if(empty($_GET['tags_type']) && !empty($TagList) && count($TagList) > 1) { + $_GET['tags_type'] = '0'; + if(!empty($TagListEx)) { + $Queries[]='@taglist ( '.implode(' | ', $TagList).' ) '.implode(' ', $TagListEx); + } else { + $Queries[]='@taglist ( '.implode(' | ', $TagList).' )'; + } +} elseif(!empty($TagList)) { + $Queries[]='@taglist '.implode(' ', array_merge($TagList,$TagListEx)); +} else { + $_GET['tags_type'] = '1'; +} + +foreach(array('artistname','groupname', 'recordlabel', 'cataloguenumber', + 'remastertitle', 'remasteryear', 'remasterrecordlabel', 'remastercataloguenumber', + 'filelist', 'format', 'media') as $Search) { + if(!empty($_GET[$Search])) { + $_GET[$Search] = str_replace(array('%'), '', $_GET[$Search]); + if($Search == 'filelist') { + $Queries[]='@filelist "'.$SS->EscapeString($_GET['filelist']).'"~20'; + } else { + $Words = explode(' ', $_GET[$Search]); + foreach($Words as $Key => &$Word) { + if($Word[0] == '!' && strlen($Word) >= 3 && count($Words) >= 2) { + if(strpos($Word,'!',1) === false) { + $Word = '!'.$SS->EscapeString(substr($Word,1)); + } else { + $Word = $SS->EscapeString($Word); + } + } elseif(strlen($Word) >= 2) { + $Word = $SS->EscapeString($Word); + } else { + unset($Words[$Key]); + } + } + $Words = trim(implode(' ',$Words)); + if(!empty($Words)) { + $Queries[]="@$Search ".$Words; + } + } + } +} + +if(!empty($_GET['year'])) { + $Years = explode('-', $_GET['year']); + if(is_number($Years[0]) || (empty($Years[0]) && !empty($Years[1]) && is_number($Years[1]))) { + if(count($Years) == 1) { + $SS->set_filter('year', array((int)$Years[0])); + } else { + if(empty($Years[1]) || !is_number($Years[1])) { + $Years[1] = PHP_INT_MAX; + } elseif($Years[0] > $Years[1]) { + $Years = array_reverse($Years); + } + $SS->set_filter_range('year', (int)$Years[0], (int)$Years[1]); + } + } +} +if(!empty($_GET['encoding'])) { + $Queries[]='@encoding "'.$SS->EscapeString($_GET['encoding']).'"'; // Note the quotes, for 24bit lossless +} + +if(isset($_GET['haslog']) && $_GET['haslog']!=='') { + if($_GET['haslog'] == 100) { + $SS->set_filter('logscore', array(100)); + } elseif ($_GET['haslog'] < 0) { + // Exclude torrents with log score equal to 100 + $SS->set_filter('logscore', array(100), true); + $SS->set_filter('haslog', array(1)); + } else { + $SS->set_filter('haslog', array(1)); + } +} + +foreach(array('hascue','scene','vanityhouse','freetorrent','releasetype') as $Search) { + if(isset($_GET[$Search]) && $_GET[$Search]!=='') { + if($Search == 'freetorrent') { + switch($_GET[$Search]) { + case 0: $SS->set_filter($Search, array(0)); break; + case 1: $SS->set_filter($Search, array(1)); break; + case 2: $SS->set_filter($Search, array(2)); break; + case 3: $SS->set_filter($Search, array(0), true); break; + } + } else { + $SS->set_filter($Search, array($_GET[$Search])); + } + } +} + + +if(!empty($_GET['filter_cat'])) { + $SS->set_filter('categoryid', array_keys($_GET['filter_cat'])); +} + + +if(!empty($_GET['page']) && is_number($_GET['page'])) { + if(check_perms('site_search_many')) { + $Page = $_GET['page']; + } else { + $Page = min(SPHINX_MAX_MATCHES/TORRENTS_PER_PAGE, $_GET['page']); + } + $MaxMatches = min(SPHINX_MAX_MATCHES, SPHINX_MATCHES_START + SPHINX_MATCHES_STEP*floor(($Page-1)*TORRENTS_PER_PAGE/SPHINX_MATCHES_STEP)); + $SS->limit(($Page-1)*TORRENTS_PER_PAGE, TORRENTS_PER_PAGE, $MaxMatches); +} else { + $Page = 1; + $MaxMatches = SPHINX_MATCHES_START; + $SS->limit(0, TORRENTS_PER_PAGE); +} + +if(!empty($_GET['order_way']) && $_GET['order_way'] == 'asc') { + $Way = SPH_SORT_ATTR_ASC; + $OrderWay = 'asc'; // For header links +} else { + $Way = SPH_SORT_ATTR_DESC; + $_GET['order_way'] = 'desc'; + $OrderWay = 'desc'; +} + +if(empty($_GET['order_by']) || !in_array($_GET['order_by'], array('year','time','size','seeders','leechers','snatched','random'))) { + $_GET['order_by'] = 'time'; + $OrderBy = 'time'; // For header links +} elseif($_GET['order_by'] == 'random') { + $OrderBy = '@random'; + $Way = SPH_SORT_EXTENDED; + $SS->limit(0, TORRENTS_PER_PAGE, TORRENTS_PER_PAGE); +} else { + $OrderBy = $_GET['order_by']; +} + +$SS->SetSortMode($Way, $OrderBy); + + +if(count($Queries)>0) { + $Query = implode(' ',$Queries); +} else { + $Query=''; + if(empty($SS->Filters)) { + $SS->set_filter('size', array(0), true); + } +} + +$SS->set_index(SPHINX_INDEX.' delta'); +$Results = $SS->search($Query, '', 0, array(), '', ''); +$TorrentCount = $SS->TotalResults; + +// These ones were not found in the cache, run SQL +if(!empty($Results['notfound'])) { + $SQLResults = get_groups($Results['notfound']); + + if(is_array($SQLResults['notfound'])) { // Something wasn't found in the db, remove it from results + reset($SQLResults['notfound']); + foreach($SQLResults['notfound'] as $ID) { + unset($SQLResults['matches'][$ID]); + unset($Results['matches'][$ID]); + } + } + + // Merge SQL results with sphinx/memcached results + foreach($SQLResults['matches'] as $ID=>$SQLResult) { + $Results['matches'][$ID] = array_merge($Results['matches'][$ID], $SQLResult); + ksort($Results['matches'][$ID]); + } +} + +$Results = $Results['matches']; + +$AdvancedSearch = false; +$Action = 'action=basic'; +if(((!empty($_GET['action']) && strtolower($_GET['action'])=="advanced") || (!empty($LoggedUser['SearchType']) && ((!empty($_GET['action']) && strtolower($_GET['action'])!="basic") || empty($_GET['action'])))) && check_perms('site_advanced_search')) { + $AdvancedSearch = true; + $Action = 'action=advanced'; +} + + +if(count($Results)==0) { +$DB->query("SELECT + tags.Name, + ((COUNT(tags.Name)-2)*(SUM(tt.PositiveVotes)-SUM(tt.NegativeVotes)))/(tags.Uses*0.8) AS Score + FROM xbt_snatched AS s + INNER JOIN torrents AS t ON t.ID=s.fid + INNER JOIN torrents_group AS g ON t.GroupID=g.ID + INNER JOIN torrents_tags AS tt ON tt.GroupID=g.ID + INNER JOIN tags ON tags.ID=tt.TagID + WHERE s.uid='$LoggedUser[ID]' + AND tt.TagID<>'13679' + AND tt.TagID<>'4820' + AND tt.TagID<>'2838' + AND g.CategoryID='1' + AND tags.Uses > '10' + GROUP BY tt.TagID + ORDER BY Score DESC + LIMIT 8"); + + $JsonYouMightLike = array(); + while(list($Tag)=$DB->next_record()) { + $JsonYouMightLike[] = $Tag; + } + + print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'results' => array(), + 'youMightLike' => $JsonYouMightLike + ) + ) + ); + die(); +} + +$Bookmarks = all_bookmarks('torrent'); + +$JsonGroups = array(); +foreach($Results as $GroupID=>$Data) { + list($Artists, $GroupCatalogueNumber, $ExtendedArtists, $GroupID2, $GroupName, $GroupRecordLabel, $ReleaseType, $TagList, $Torrents, $GroupVanityHouse, $GroupYear, $CategoryID, $FreeTorrent, $HasCue, $HasLog, $TotalLeechers, $LogScore, $ReleaseType, $ReleaseType, $TotalSeeders, $MaxSize, $TotalSnatched, $GroupTime) = array_values($Data); + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + if(count($Torrents)>1 || $CategoryID==1) { + // These torrents are in a group + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName = display_artists($ExtendedArtists, false, false, true); + } elseif(!empty($Artists)) { + $DisplayName = display_artists(array(1=>$Artists), false, false, true); + } else { + $DisplayName=''; + } + + $LastRemasterYear = '-'; + $LastRemasterTitle = ''; + $LastRemasterRecordLabel = ''; + $LastRemasterCatalogueNumber = ''; + $LastMedia = ''; + + $EditionID = 0; + unset($FirstUnknown); + + $JsonTorrents = array(); + foreach($Torrents as $TorrentID => $Data) { + // All of the individual torrents in the group + + // If they're using the advanced search and have chosen enabled grouping, we just skip the torrents that don't check out + + $Filter = false; + $Pass = false; + + if(!empty($FilterBitrates)) { + $Filter = true; + $Bitrate = strtolower(array_shift(explode(' ',$Data['Encoding']))); + if(in_array($Bitrate, $FilterBitrates)) { + $Pass = true; + } + } + if(!empty($FilterFormats)) { + $Filter = true; + if(in_array(strtolower($Data['Format']), $FilterFormats)) { + $Pass = true; + } + } + + if(!empty($_GET['encoding'])) { + $Filter = true; + if($Data['Encoding']==$_GET['encoding']) { + $Pass = true; + } + } + if(!empty($_GET['format'])) { + $Filter = true; + if($Data['Format']==$_GET['format']) { + $Pass = true; + } + } + + + if(!empty($_GET['media'])) { + $Filter = true; + if($Data['Media']==$_GET['media']) { + $Pass = true; + } + } + if(isset($_GET['haslog']) && $_GET['haslog']!=='') { + $Filter = true; + if($_GET['haslog'] == '100' && $Data['LogScore']==100) { + $Pass = true; + } elseif (($_GET['haslog'] == '-1') && ($Data['LogScore'] < 100) && ($Data['HasLog'] == '1')) { + $Pass = true; + } elseif(($_GET['haslog'] == '1' || $_GET['haslog'] == '0') && (int)$Data['HasLog']==$_GET['haslog']) { + $Pass = true; + } + } + if(isset($_GET['hascue']) && $_GET['hascue']!=='') { + $Filter = true; + if((int)$Data['HasCue']==$_GET['hascue']) { + $Pass = true; + } + } + if(isset($_GET['scene']) && $_GET['scene']!=='') { + $Filter = true; + if((int)$Data['Scene']==$_GET['scene']) { + $Pass = true; + } + } + if(isset($_GET['vanityhouse']) && $_GET['vanityhouse']!=='') { + $Filter = true; + if((int)$Data['VanityHouse']==$_GET['vanityhouse']) { + $Pass = true; + } + } + if(isset($_GET['freetorrent']) && $_GET['freetorrent']!=='') { + $Filter = true; + if((int)$Data['FreeTorrent'] & $_GET['freetorrent'] || (int)$Data['FreeTorrent'] == $_GET['freetorrent']) { + $Pass = true; + } + } + if(!empty($_GET['remastertitle'])) { + $Filter = true; + $Continue = false; + $RemasterParts = explode(' ', $_GET['remastertitle']); + foreach($RemasterParts as $RemasterPart) { + if(stripos($Data['RemasterTitle'],$RemasterPart) === false) { + $Continue = true; + } + } + if(!$Continue) { + $Pass = true; + } + } + if($Filter && !$Pass) { + continue; + } + + if ($Data['Remastered'] && !$Data['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if (in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent'])) { + $Data['PersonalFL'] = 1; + } + + if($CategoryID == 1 && ($Data['RemasterTitle'] != $LastRemasterTitle || $Data['RemasterYear'] != $LastRemasterYear || + $Data['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Data['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber) || $FirstUnknown || $Data['Media'] != $LastMedia) { + $EditionID++; + + if($Data['Remastered'] && $Data['RemasterYear'] != 0) { + + $RemasterName = $Data['RemasterYear']; + $AddExtra = " - "; + if($Data['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Data['RemasterRecordLabel']); $AddExtra=' / '; } + if($Data['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Data['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Data['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Data['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Data['Media']); + } else { + $AddExtra = " / "; + if (!$Data['Remastered']) { + $MasterName = "Original Release"; + if($GroupRecordLabel) { $MasterName .= $AddExtra.$GroupRecordLabel; $AddExtra=' / '; } + if($GroupCatalogueNumber) { $MasterName .= $AddExtra.$GroupCatalogueNumber; $AddExtra=' / '; } + } else { + $MasterName = "Unknown Release(s)"; + } + $MasterName .= $AddExtra.display_str($Data['Media']); + } + } + $LastRemasterTitle = $Data['RemasterTitle']; + $LastRemasterYear = $Data['RemasterYear']; + $LastRemasterRecordLabel = $Data['RemasterRecordLabel']; + $LastRemasterCatalogueNumber = $Data['RemasterCatalogueNumber']; + $LastMedia = $Data['Media']; + + $JsonTorrents[] = array( + 'torrentId' => (int) $TorrentID, + 'editionId' => (int) $EditionID, + 'remastered' => $Data['Remastered'] == '1', + 'remasterYear' => (int) $Data['RemasterYear'], + 'remasterCatalogueNumber' => $Data['RemasterCatalogueNumber'], + 'remasterTitle' => $Data['RemasterTitle'], + 'media' => $Data['Media'], + 'encoding' => $Data['Encoding'], + 'format' => $Data['Format'], + 'hasLog' => $Data['HasLog'] == '1', + 'logScore' => (int) $Data['LogScore'], + 'hasCue' => $Data['HasCue'] == '1', + 'scene' => $Data['Scene'] == '1', + 'vanityHouse' => $Data['VanityHouse'] == '1', + 'fileCount' => (int) $Data['FileCount'], + 'time' => $Data['Time'], + 'size' => (int) $Data['Size'], + 'snatches' => (int) $Data['Snatched'], + 'seeders' => (int) $Data['Seeders'], + 'leechers' => (int) $Data['Leechers'], + 'isFreeleech' => $Data['FreeTorrent'] == '1', + 'isNeutralLeech' => $Data['FreeTorrent'] == '2', + 'isPersonalFreeleech' => in_array($TorrentID, $TokenTorrents), + 'canUseToken' => ($LoggedUser['FLTokens'] > 0) + && $Data['HasFile'] && ($Data['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) + && empty($Data['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1') + ); + } + + $JsonGroups[] = array( + 'groupId' => (int) $GroupID, + 'groupName' => $GroupName, + 'artist' => $DisplayName, + 'tags' => $TagList, + 'bookmarked' => in_array($GroupID, $Bookmarks), + 'vanityHouse' => $GroupVanityHouse == '1', + 'groupYear' => (int) $GroupYear, + 'releaseType' => $ReleaseTypes[$ReleaseType], + 'groupTime' => $GroupTime, + 'maxSize' => (int) $MaxSize, + 'totalSnatched' => (int) $TotalSnatched, + 'totalSeeders' => (int) $TotalSeeders, + 'totalLeechers' => (int) $TotalLeechers, + 'torrents' => $JsonTorrents + ); + } + else { + // Viewing a type that does not require grouping + + list($TorrentID, $Data) = each($Torrents); + + $JsonGroups[] = array( + 'groupId' => (int) $GroupID, + 'groupName' => $GroupName, + 'torrentId' => (int) $TorrentID, + 'tags' => $TagList, + 'category' => $Categories[$CategoryID-1], + 'fileCount' => (int) $Data['FileCount'], + 'groupTime' => $GroupTime, + 'size' => (int) $Data['Size'], + 'snatches' => (int) $TotalSnatched, + 'seeders' => (int) $TotalSeeders, + 'leechers' => (int) $TotalLeechers, + 'isFreeleech' => $Data['FreeTorrent'] == '1', + 'isNeutralLeech' => $Data['FreeTorrent'] == '2', + 'isPersonalFreeleech' => in_array($TorrentID, $TokenTorrents), + 'canUseToken' => ($LoggedUser['FLTokens'] > 0) + && $Data['HasFile'] && ($Data['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) + && empty($Data['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1') + ); + } +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'currentPage' => intval($Page), + 'pages' => ceil($TorrentCount/TORRENTS_PER_PAGE), + 'results' => $JsonGroups + ) + ) + ); diff --git a/sections/ajax/forum/forum.php b/sections/ajax/forum/forum.php new file mode 100644 index 00000000..5e2c506b --- /dev/null +++ b/sections/ajax/forum/forum.php @@ -0,0 +1,157 @@ + 'failure')); + die(); +} + +if (isset($_GET['pp'])) { + $PerPage = $_GET['pp']; +} +else if (isset($LoggedUser['PostsPerPage'])) { + $PerPage = $LoggedUser['PostsPerPage']; +} else { + $PerPage = POSTS_PER_PAGE; +} + +list($Page,$Limit) = page_limit(TOPICS_PER_PAGE); + +//---------- Get some data to start processing + +// Caching anything beyond the first page of any given forum is just wasting ram +// users are more likely to search then to browse to page 2 +if($Page==1) { + list($Forum,,,$Stickies) = $Cache->get_value('forums_'.$ForumID); +} +if(!isset($Forum) || !is_array($Forum)) { + $DB->query("SELECT + t.ID, + t.Title, + t.AuthorID, + author.Username AS AuthorUsername, + t.IsLocked, + t.IsSticky, + t.NumPosts, + t.LastPostID, + t.LastPostTime, + t.LastPostAuthorID, + last_author.Username AS LastPostUsername + FROM forums_topics AS t + LEFT JOIN users_main AS last_author ON last_author.ID = t.LastPostAuthorID + LEFT JOIN users_main AS author ON author.ID = t.AuthorID + WHERE t.ForumID = '$ForumID' + ORDER BY t.IsSticky DESC, t.LastPostTime DESC + LIMIT $Limit"); // Can be cached until someone makes a new post + $Forum = $DB->to_array('ID',MYSQLI_ASSOC); + if($Page==1) { + $DB->query("SELECT COUNT(ID) FROM forums_topics WHERE ForumID='$ForumID' AND IsSticky='1'"); + list($Stickies) = $DB->next_record(); + $Cache->cache_value('forums_'.$ForumID, array($Forum,'',0,$Stickies), 0); + } +} + +if(!isset($Forums[$ForumID])) { + print json_encode(array('status' => 'failure')); + die(); +} +// Make sure they're allowed to look at the page +if (!check_perms('site_moderate_forums')) { + if (isset($LoggedUser['CustomForums'][$ForumID]) && $LoggedUser['CustomForums'][$ForumID] === 0) { error(403); } +} +if($LoggedUser['CustomForums'][$ForumID] != 1 && $Forums[$ForumID]['MinClassRead'] > $LoggedUser['Class']) { error(403); } + +$JsonSpecificRules = array(); +foreach ($Forums[$ForumID]['SpecificRules'] as $ThreadIDs) { + $Thread = get_thread_info($ThreadIDs); + $JsonSpecificRules[] = array( + 'threadId' => (int) $ThreadIDs, + 'thread' => $Thread['Title'] + ); +} + +$Pages=get_pages($Page,$Forums[$ForumID]['NumTopics'],TOPICS_PER_PAGE,9); + +if (count($Forum) == 0) { + print + json_encode( + array( + 'status' => 'success', + 'forumName' => $Forums[$ForumID]['Name'], + 'threads' => array() + ) + ); +} +else { + // forums_last_read_topics is a record of the last post a user read in a topic, and what page that was on + $DB->query('SELECT + l.TopicID, + l.PostID, + CEIL((SELECT COUNT(ID) FROM forums_posts WHERE forums_posts.TopicID = l.TopicID AND forums_posts.ID<=l.PostID)/'.$PerPage.') AS Page + FROM forums_last_read_topics AS l + WHERE TopicID IN('.implode(', ', array_keys($Forum)).') AND + UserID=\''.$LoggedUser['ID'].'\''); + + // Turns the result set into a multi-dimensional array, with + // forums_last_read_topics.TopicID as the key. + // This is done here so we get the benefit of the caching, and we + // don't have to make a database query for each topic on the page + $LastRead = $DB->to_array('TopicID'); + + $JsonTopics = array(); + foreach ($Forum as $Topic) { + list($TopicID, $Title, $AuthorID, $AuthorName, $Locked, $Sticky, $PostCount, $LastID, $LastTime, $LastAuthorID, $LastAuthorName) = array_values($Topic); + + // handle read/unread posts - the reason we can't cache the whole page + if((!$Locked || $Sticky) && ((empty($LastRead[$TopicID]) || $LastRead[$TopicID]['PostID']<$LastID) && strtotime($LastTime)>$LoggedUser['CatchupTime'])) { + $Read = 'unread'; + } else { + $Read = 'read'; + } + + $JsonTopics[] = array( + 'topicId' => (int) $TopicID, + 'title' => $Title, + 'authorId' => (int) $AuthorID, + 'authorName' => $AuthorName, + 'locked' => $Locked == 1, + 'sticky' => $Sticky == 1, + 'postCount' => (int) $PostCount, + 'lastID' => $LastID == null ? 0 : (int) $LastID, + 'lastTime' => $LastTime, + 'lastAuthorId' => $LastAuthorID == null ? 0 : (int) $LastAuthorID, + 'lastAuthorName' => $LastAuthorName == null ? "" : $LastAuthorName, + 'lastReadPage' => $LastRead[$TopicID]['Page'] == null ? 0 : (int) $LastRead[$TopicID]['Page'], + 'lastReadPostId' => $LastRead[$TopicID]['PostID'] == null ? 0 : (int) $LastRead[$TopicID]['PostID'] + ); + } + + print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'forumName' => $Forums[$ForumID]['Name'], + 'specificRules' => $JsonSpecificRules, + 'currentPage' => (int) $Page, + 'pages' => ceil($Forums[$ForumID]['NumTopics']/TOPICS_PER_PAGE), + 'threads' => $JsonTopics + ) + ) + ); +} +?> diff --git a/sections/ajax/forum/index.php b/sections/ajax/forum/index.php new file mode 100644 index 00000000..d16b8649 --- /dev/null +++ b/sections/ajax/forum/index.php @@ -0,0 +1,107 @@ + 'failure')); + die(); +} +else { + include(SERVER_ROOT.'/sections/forums/functions.php'); + // Replace the old hard-coded forum categories + unset($ForumCats); + $ForumCats = $Cache->get_value('forums_categories'); + if ($ForumCats === false) { + $DB->query("SELECT ID, Name FROM forums_categories"); + $ForumCats = array(); + while (list($ID, $Name) = $DB->next_record()) { + $ForumCats[$ID] = $Name; + } + $Cache->cache_value('forums_categories', $ForumCats, 0); //Inf cache. + } + + //This variable contains all our lovely forum data + if(!$Forums = $Cache->get_value('forums_list')) { + $DB->query("SELECT + f.ID, + f.CategoryID, + f.Name, + f.Description, + f.MinClassRead, + f.MinClassWrite, + f.MinClassCreate, + f.NumTopics, + f.NumPosts, + f.LastPostID, + f.LastPostAuthorID, + um.Username, + f.LastPostTopicID, + f.LastPostTime, + COUNT(sr.ThreadID) AS SpecificRules, + t.Title, + t.IsLocked, + t.IsSticky + FROM forums AS f + JOIN forums_categories AS fc ON fc.ID = f.CategoryID + LEFT JOIN forums_topics as t ON t.ID = f.LastPostTopicID + LEFT JOIN users_main AS um ON um.ID=f.LastPostAuthorID + LEFT JOIN forums_specific_rules AS sr ON sr.ForumID = f.ID + GROUP BY f.ID + ORDER BY fc.Sort, fc.Name, f.CategoryID, f.Sort"); + $Forums = $DB->to_array('ID', MYSQLI_ASSOC, false); + foreach($Forums as $ForumID => $Forum) { + if(count($Forum['SpecificRules'])) { + $DB->query("SELECT ThreadID FROM forums_specific_rules WHERE ForumID = ".$ForumID); + $ThreadIDs = $DB->collect('ThreadID'); + $Forums[$ForumID]['SpecificRules'] = $ThreadIDs; + } + } + unset($ForumID, $Forum); + $Cache->cache_value('forums_list', $Forums, 0); //Inf cache. + } + + if(empty($_GET['type']) || $_GET['type'] == 'main') { + include(SERVER_ROOT.'/sections/ajax/forum/main.php'); + } else { + switch($_GET['type']) { + case 'viewforum': + include(SERVER_ROOT.'/sections/ajax/forum/forum.php'); + break; + case 'viewthread': + include(SERVER_ROOT.'/sections/ajax/forum/thread.php'); + break; + default: + print json_encode(array('status' => 'failure')); + break; + } + } +} + +// Function to get basic information on a forum +// Uses class CACHE +function get_forum_info($ForumID) { + global $DB, $Cache; + $Forum = $Cache->get_value('ForumInfo_'.$ForumID); + if(!$Forum) { + $DB->query("SELECT + Name, + MinClassRead, + MinClassWrite, + MinClassCreate, + COUNT(forums_topics.ID) AS Topics + FROM forums + LEFT JOIN forums_topics ON forums_topics.ForumID=forums.ID + WHERE forums.ID='$ForumID' + GROUP BY ForumID"); + if($DB->record_count() == 0) { + return false; + } + // Makes an array, with $Forum['Name'], etc. + $Forum = $DB->next_record(MYSQLI_ASSOC); + + $Cache->cache_value('ForumInfo_'.$ForumID, $Forum, 86400); // Cache for a day + } + return $Forum; +} + +?> diff --git a/sections/ajax/forum/main.php b/sections/ajax/forum/main.php new file mode 100644 index 00000000..820a8fd9 --- /dev/null +++ b/sections/ajax/forum/main.php @@ -0,0 +1,93 @@ +query("SELECT + l.TopicID, + l.PostID, + CEIL((SELECT COUNT(ID) FROM forums_posts WHERE forums_posts.TopicID = l.TopicID AND forums_posts.ID<=l.PostID)/$PerPage) AS Page + FROM forums_last_read_topics AS l + WHERE TopicID IN(".implode(',',$TopicIDs).") AND + UserID='$LoggedUser[ID]'"); + $LastRead = $DB->to_array('TopicID', MYSQLI_ASSOC); +} else { + $LastRead = array(); +} + +$DB->query("SELECT RestrictedForums FROM users_info WHERE UserID = ".$LoggedUser['ID']); +list($RestrictedForums) = $DB->next_record(); +$RestrictedForums = explode(',', $RestrictedForums); +$PermittedForums = array_keys($LoggedUser['PermittedForums']); + +$JsonCategories = array(); +$JsonCategory = array(); +$JsonForums = array(); +foreach ($Forums as $Forum) { + list($ForumID, $CategoryID, $ForumName, $ForumDescription, $MinRead, $MinWrite, $MinCreate, $NumTopics, $NumPosts, $LastPostID, $LastAuthorID, $LastPostAuthorName, $LastTopicID, $LastTime, $SpecificRules, $LastTopic, $Locked, $Sticky) = array_values($Forum); + if ($LoggedUser['CustomForums'][$ForumID] != 1 && ($MinRead>$LoggedUser['Class'] || array_search($ForumID, $RestrictedForums) !== FALSE)) { + continue; + } + $ForumDescription = display_str($ForumDescription); + + if($CategoryID!=$LastCategoryID) { + if (!empty($JsonForums) && !empty($JsonCategory)) { + $JsonCategory['forums'] = $JsonForums; + $JsonCategories[] = $JsonCategory; + } + $LastCategoryID = $CategoryID; + $JsonCategory = array( + 'categoryID' => (int) $CategoryID, + 'categoryName' => $ForumCats[$CategoryID] + ); + $JsonForums = array(); + } + + if((!$Locked || $Sticky) && $LastPostID != 0 && ((empty($LastRead[$LastTopicID]) || $LastRead[$LastTopicID]['PostID'] < $LastPostID) && strtotime($LastTime)>$LoggedUser['CatchupTime'])) { + $Read = 'unread'; + } else { + $Read = 'read'; + } + + $JsonForums[] = array( + 'forumId' => (int) $ForumID, + 'forumName' => $ForumName, + 'forumDescription' => $ForumDescription, + 'numTopics' => (float) $NumTopics, + 'numPosts' => (float) $NumPosts, + 'lastPostId' => (float) $LastPostID, + 'lastAuthorId' => (float) $LastAuthorID, + 'lastPostAuthorName' => $LastPostAuthorName, + 'lastTopicId' => (float) $LastTopicID, + 'lastTime' => $LastTime, + 'specificRules' => $SpecificRules, + 'lastTopic' => $LastTopic, + 'read' => $Read == 1, + 'locked' => $Locked == 1, + 'sticky' => $Sticky == 1 + ); +} + +print json_encode( + array( + 'status' => 'success', + 'response' => array( + 'categories' => $JsonCategories + ) + ) +); diff --git a/sections/ajax/forum/thread.php b/sections/ajax/forum/thread.php new file mode 100644 index 00000000..98eaac6d --- /dev/null +++ b/sections/ajax/forum/thread.php @@ -0,0 +1,262 @@ +query("SELECT TopicID FROM forums_posts WHERE ID = $_GET[postid]"); + list($ThreadID) = $DB->next_record(); + if($ThreadID) { + header("Location: ajax.php?action=forum&type=viewthread&threadid=$ThreadID&postid=$_GET[postid]"); + die(); + } else { + print json_encode(array('status' => 'failure')); + die(); + } + } else { + print json_encode(array('status' => 'failure')); + die(); + } +} else { + $ThreadID = $_GET['threadid']; +} + +if (isset($_GET['pp'])) { + $PerPage = $_GET['pp']; +} +else if (isset($LoggedUser['PostsPerPage'])) { + $PerPage = $LoggedUser['PostsPerPage']; +} else { + $PerPage = POSTS_PER_PAGE; +} + +//---------- Get some data to start processing + +// Thread information, constant across all pages +$ThreadInfo = get_thread_info($ThreadID, true, true); +$ForumID = $ThreadInfo['ForumID']; + +// Make sure they're allowed to look at the page +if(!check_forumperm($ForumID)) { + print json_encode(array('status' => 'failure')); + die(); +} + +//Post links utilize the catalogue & key params to prevent issues with custom posts per page +if($ThreadInfo['Posts'] > $PerPage) { + if(isset($_GET['post']) && is_number($_GET['post'])) { + $PostNum = $_GET['post']; + } elseif(isset($_GET['postid']) && is_number($_GET['postid'])) { + $DB->query("SELECT COUNT(ID) FROM forums_posts WHERE TopicID = $ThreadID AND ID <= $_GET[postid]"); + list($PostNum) = $DB->next_record(); + } else { + $PostNum = 1; + } +} else { + $PostNum = 1; +} +list($Page,$Limit) = page_limit($PerPage, min($ThreadInfo['Posts'],$PostNum)); +list($CatalogueID,$CatalogueLimit) = catalogue_limit($Page,$PerPage,THREAD_CATALOGUE); + +// Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page +if(!$Catalogue = $Cache->get_value('thread_'.$ThreadID.'_catalogue_'.$CatalogueID)) { + $DB->query("SELECT + p.ID, + p.AuthorID, + p.AddedTime, + p.Body, + p.EditedUserID, + p.EditedTime, + ed.Username + FROM forums_posts as p + LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID + WHERE p.TopicID = '$ThreadID' AND p.ID != '".$ThreadInfo['StickyPostID']."' + LIMIT $CatalogueLimit"); + $Catalogue = $DB->to_array(false,MYSQLI_ASSOC); + if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) { + $Cache->cache_value('thread_'.$ThreadID.'_catalogue_'.$CatalogueID, $Catalogue, 0); + } +} +$Thread = catalogue_select($Catalogue,$Page,$PerPage,THREAD_CATALOGUE); + +$LastPost = end($Thread); +$LastPost = $LastPost['ID']; +reset($Thread); + +if ($_GET['updatelastread'] != '0') { + //Handle last read + if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) { + $DB->query("SELECT PostID From forums_last_read_topics WHERE UserID='$LoggedUser[ID]' AND TopicID='$ThreadID'"); + list($LastRead) = $DB->next_record(); + if($LastRead < $LastPost) { + $DB->query("INSERT INTO forums_last_read_topics + (UserID, TopicID, PostID) VALUES + ('$LoggedUser[ID]', '".$ThreadID ."', '".db_string($LastPost)."') + ON DUPLICATE KEY UPDATE PostID='$LastPost'"); + } + } +} + +//Handle subscriptions +if(($UserSubscriptions = $Cache->get_value('subscriptions_user_'.$LoggedUser['ID'])) === FALSE) { + $DB->query("SELECT TopicID FROM users_subscriptions WHERE UserID = '$LoggedUser[ID]'"); + $UserSubscriptions = $DB->collect(0); + $Cache->cache_value('subscriptions_user_'.$LoggedUser['ID'],$UserSubscriptions,0); +} + +if(empty($UserSubscriptions)) { + $UserSubscriptions = array(); +} + +if(in_array($ThreadID, $UserSubscriptions)) { + $Cache->delete_value('subscriptions_user_new_'.$LoggedUser['ID']); +} + +$JsonPoll = array(); +if ($ThreadInfo['NoPoll'] == 0) { + if (!list($Question,$Answers,$Votes,$Featured,$Closed) = $Cache->get_value('polls_'.$ThreadID)) { + $DB->query("SELECT Question, Answers, Featured, Closed FROM forums_polls WHERE TopicID='".$ThreadID."'"); + list($Question, $Answers, $Featured, $Closed) = $DB->next_record(MYSQLI_NUM, array(1)); + $Answers = unserialize($Answers); + $DB->query("SELECT Vote, COUNT(UserID) FROM forums_polls_votes WHERE TopicID='$ThreadID' GROUP BY Vote"); + $VoteArray = $DB->to_array(false, MYSQLI_NUM); + + $Votes = array(); + foreach ($VoteArray as $VoteSet) { + list($Key,$Value) = $VoteSet; + $Votes[$Key] = $Value; + } + + foreach(array_keys($Answers) as $i) { + if (!isset($Votes[$i])) { + $Votes[$i] = 0; + } + } + $Cache->cache_value('polls_'.$ThreadID, array($Question,$Answers,$Votes,$Featured,$Closed), 0); + } + + if (!empty($Votes)) { + $TotalVotes = array_sum($Votes); + $MaxVotes = max($Votes); + } else { + $TotalVotes = 0; + $MaxVotes = 0; + } + + $RevealVoters = in_array($ForumID, $ForumsRevealVoters); + //Polls lose the you voted arrow thingy + $DB->query("SELECT Vote FROM forums_polls_votes WHERE UserID='".$LoggedUser['ID']."' AND TopicID='$ThreadID'"); + list($UserResponse) = $DB->next_record(); + if (!empty($UserResponse) && $UserResponse != 0) { + $Answers[$UserResponse] = '» '.$Answers[$UserResponse]; + } else { + if(!empty($UserResponse) && $RevealVoters) { + $Answers[$UserResponse] = '» '.$Answers[$UserResponse]; + } + } + + $JsonPoll['closed'] = $Closed == 1; + $JsonPoll['featured'] = $Featured; + $JsonPoll['question'] = $Question; + $JsonPoll['maxVotes'] = (int) $MaxVotes; + $JsonPoll['totalVotes'] = $TotalVotes; + $JsonPollAnswers = array(); + + foreach($Answers as $i => $Answer) { + if (!empty($Votes[$i]) && $TotalVotes > 0) { + $Ratio = $Votes[$i]/$MaxVotes; + $Percent = $Votes[$i]/$TotalVotes; + } else { + $Ratio=0; + $Percent=0; + } + $JsonPollAnswers[] = array( + 'answer' => $Answer, + 'ratio' => $Ratio, + 'percent' => $Percent + ); + } + + if ($UserResponse !== null || $Closed || $ThreadInfo['IsLocked'] || $LoggedUser['Class'] < $Forums[$ForumID]['MinClassWrite']) { + $JsonPoll['voted'] = True; + } else { + $JsonPoll['voted'] = False; + } + + $JsonPoll['answers'] = $JsonPollAnswers; +} + +//Sqeeze in stickypost +if($ThreadInfo['StickyPostID']) { + if($ThreadInfo['StickyPostID'] != $Thread[0]['ID']) { + array_unshift($Thread, $ThreadInfo['StickyPost']); + } + if($ThreadInfo['StickyPostID'] != $Thread[count($Thread)-1]['ID']) { + $Thread[] = $ThreadInfo['StickyPost']; + } +} + +$JsonPosts = array(); +foreach ($Thread as $Key => $Post) { + list($PostID, $AuthorID, $AddedTime, $Body, $EditedUserID, $EditedTime, $EditedUsername) = array_values($Post); + list($AuthorID, $Username, $PermissionID, $Paranoia, $Artist, $Donor, $Warned, $Avatar, $Enabled, $UserTitle) = array_values(user_info($AuthorID)); + $JsonPosts[] = array( + 'postId' => (int) $PostID, + 'addedTime' => $AddedTime, + 'body' => $Text->full_format($Body), + 'editedUserId' => (int) $EditedUserID, + 'editedTime' => $EditedTime, + 'editedUsername' => $EditedUsername, + 'author' => array( + 'authorId' => (int) $AuthorID, + 'authorName' => $Username, + 'paranoia' => $Paranoia, + 'artist' => $Artist == 1, + 'donor' => $Donor == 1, + 'warned' => ($Warned!='0000-00-00 00:00:00'), + 'avatar' => $Avatar, + 'enabled' => $Enabled == 2 ? false : true, + 'userTitle' => $UserTitle + ), + + ); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'forumId' => (int) $ForumID, + 'forumName' => $Forums[$ForumID]['Name'], + 'threadId' => (int) $ThreadID, + 'threadTitle' => $ThreadInfo['Title'], + 'subscribed' => in_array($ThreadID, $UserSubscriptions), + 'locked' => $ThreadInfo['IsLocked'] == 1, + 'sticky' => $ThreadInfo['IsSticky'] == 1, + 'currentPage' => (int) $Page, + 'pages' => ceil($ThreadInfo['Posts']/$PerPage), + 'poll' => empty($JsonPoll) ? null : $JsonPoll, + 'posts' => $JsonPosts + ) + ) + ); diff --git a/sections/ajax/giveback_report.php b/sections/ajax/giveback_report.php new file mode 100644 index 00000000..c76f2095 --- /dev/null +++ b/sections/ajax/giveback_report.php @@ -0,0 +1,15 @@ +query("SELECT Status FROM reportsv2 WHERE ID=".$_GET['id']); +list($Status) = $DB->next_record(); +if(isset($Status)) { + $DB->query("UPDATE reportsv2 SET Status='New', ResolverID = 0 WHERE ID=".$_GET['id']); +} +?> diff --git a/sections/ajax/grab_report.php b/sections/ajax/grab_report.php new file mode 100644 index 00000000..16521c4a --- /dev/null +++ b/sections/ajax/grab_report.php @@ -0,0 +1,16 @@ +query("UPDATE reportsv2 SET Status='New' WHERE ID=".$_GET['id']." AND Status <> 'Resolved'"); +if($DB->affected_rows() > 0) { + //Win +} else { + echo 'You just tried to grab a resolved or non existent report!'; +} +?> diff --git a/sections/ajax/inbox/inbox.php b/sections/ajax/inbox/inbox.php new file mode 100644 index 00000000..7f92f215 --- /dev/null +++ b/sections/ajax/inbox/inbox.php @@ -0,0 +1,112 @@ + 'failure' + ) + ); + die(); +} + +list($Page,$Limit) = page_limit(MESSAGES_PER_PAGE); + +$Sort = empty($_GET['sort']) || $_GET['sort'] != "unread" ? "Date DESC" : "cu.Unread = '1' DESC, DATE DESC"; + +$sql = "SELECT + SQL_CALC_FOUND_ROWS + c.ID, + c.Subject, + cu.Unread, + cu.Sticky, + cu.ForwardedTo, + um2.Username AS ForwardedName, + cu2.UserID, + um.Username, + ui.Donor, + ui.Warned, + um.Enabled,"; +$sql .= ($Section == 'sentbox')? ' cu.SentDate ' : ' cu.ReceivedDate '; +$sql .= "AS Date + FROM pm_conversations AS c + LEFT JOIN pm_conversations_users AS cu ON cu.ConvID=c.ID AND cu.UserID='$UserID' + LEFT JOIN pm_conversations_users AS cu2 ON cu2.ConvID=c.ID AND cu2.UserID!='$UserID' AND cu2.ForwardedTo=0 + LEFT JOIN users_main AS um ON um.ID=cu2.UserID + LEFT JOIN users_info AS ui ON ui.UserID=um.ID + LEFT JOIN users_main AS um2 ON um2.ID=cu.ForwardedTo"; + +if(!empty($_GET['search']) && $_GET['searchtype'] == "message") { + $sql .= " JOIN pm_messages AS m ON c.ID=m.ConvID"; +} +$sql .= " WHERE "; +if(!empty($_GET['search'])) { + $Search = db_string($_GET['search']); + if($_GET['searchtype'] == "user") { + $sql .= "um.Username LIKE '".$Search."' AND "; + } elseif($_GET['searchtype'] == "subject") { + $Words = explode(' ', $Search); + $sql .= "c.Subject LIKE '%".implode("%' AND c.Subject LIKE '%", $Words)."%' AND "; + } elseif($_GET['searchtype'] == "message") { + $Words = explode(' ', $Search); + $sql .= "m.Body LIKE '%".implode("%' AND m.Body LIKE '%", $Words)."%' AND "; + } +} +$sql .= ($Section == 'sentbox')? ' cu.InSentbox' : ' cu.InInbox'; +$sql .="='1'"; + +$sql .=" GROUP BY c.ID + ORDER BY cu.Sticky, ".$Sort." LIMIT $Limit"; +$Results = $DB->query($sql); +$DB->query('SELECT FOUND_ROWS()'); +list($NumResults) = $DB->next_record(); +$DB->set_query_id($Results); + +$CurURL = get_url(array('sort')); +if(empty($CurURL)) { + $CurURL = "inbox.php?"; +} else { + $CurURL = "inbox.php?".$CurURL."&"; +} + +$Pages=get_pages($Page,$NumResults,MESSAGES_PER_PAGE,9); + +$JsonMessages = array(); +while(list($ConvID, $Subject, $Unread, $Sticky, $ForwardedID, $ForwardedName, $SenderID, $Username, $Donor, $Warned, $Enabled, $Date) = $DB->next_record()) { + $JsonMessage = array( + 'convId' => (int) $ConvID, + 'subject' => $Subject, + 'unread' => $Unread == 1, + 'sticky' => $Sticky == 1, + 'forwardedId' => (int) $ForwardedID, + 'forwardedName' => $ForwardedName, + 'senderId' => (int) $SenderID, + 'username' => $Username, + 'donor' => $Donor == 1, + 'warned' => $Warned == 1, + 'enabled' => ($Enabled == 2 ? false : true), + 'date' => $Date + ); + $JsonMessages[] = $JsonMessage; +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'currentPage' => (int) $Page, + 'pages' => ceil($NumResults/MESSAGES_PER_PAGE), + 'messages' => $JsonMessages + ) + ) + ); +?> \ No newline at end of file diff --git a/sections/ajax/inbox/index.php b/sections/ajax/inbox/index.php new file mode 100644 index 00000000..1ce1e1b6 --- /dev/null +++ b/sections/ajax/inbox/index.php @@ -0,0 +1,14 @@ + 'failure')); + die(); +} + +?> \ No newline at end of file diff --git a/sections/ajax/inbox/viewconv.php b/sections/ajax/inbox/viewconv.php new file mode 100644 index 00000000..b49aec47 --- /dev/null +++ b/sections/ajax/inbox/viewconv.php @@ -0,0 +1,92 @@ + 'failure')); + die(); +} + + + +$UserID = $LoggedUser['ID']; +$DB->query("SELECT InInbox, InSentbox FROM pm_conversations_users WHERE UserID='$UserID' AND ConvID='$ConvID'"); +if($DB->record_count() == 0) { + print json_encode(array('status' => 'failure')); + die(); +} +list($InInbox, $InSentbox) = $DB->next_record(); + + + + +if (!$InInbox && !$InSentbox) { + print json_encode(array('status' => 'failure')); + die(); +} + +// Get information on the conversation +$DB->query("SELECT + c.Subject, + cu.Sticky, + cu.UnRead, + cu.ForwardedTo, + um.Username + FROM pm_conversations AS c + JOIN pm_conversations_users AS cu ON c.ID=cu.ConvID + LEFT JOIN users_main AS um ON um.ID=cu.ForwardedTo + WHERE c.ID='$ConvID' AND UserID='$UserID'"); +list($Subject, $Sticky, $UnRead, $ForwardedID, $ForwardedName) = $DB->next_record(); + +$DB->query("SELECT UserID, Username, PermissionID, Enabled, Donor, Warned + FROM pm_messages AS pm + JOIN users_info AS ui ON ui.UserID=pm.SenderID + JOIN users_main AS um ON um.ID=pm.SenderID + WHERE pm.ConvID='$ConvID'"); + +while(list($PMUserID, $Username, $PermissionID, $Enabled, $Donor, $Warned) = $DB->next_record()) { + $PMUserID = (int)$PMUserID; + $Users[$PMUserID]['UserStr'] = format_username($PMUserID, $Username, $Donor, $Warned, $Enabled == 2 ? false : true, $PermissionID); + $Users[$PMUserID]['Username'] = $Username; +} +$Users[0]['UserStr'] = 'System'; // in case it's a message from the system +$Users[0]['Username'] = 'System'; + + + +if($UnRead=='1') { + + $DB->query("UPDATE pm_conversations_users SET UnRead='0' WHERE ConvID='$ConvID' AND UserID='$UserID'"); + // Clear the caches of the inbox and sentbox + $Cache->decrement('inbox_new_'.$UserID); +} + +// Get messages +$DB->query("SELECT SentDate, SenderID, Body, ID FROM pm_messages AS m WHERE ConvID='$ConvID' ORDER BY ID"); + +$JsonMessages = array(); +while(list($SentDate, $SenderID, $Body, $MessageID) = $DB->next_record()) { + $JsonMessage = array( + 'messageId' => (int) $MessageID, + 'senderId' => (int) $SenderID, + 'senderName' => $Users[(int)$SenderID]['Username'], + 'sentDate' => $SentDate, + 'body' => $Text->full_format($Body) + ); + $JsonMessages[] = $JsonMessage; +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'convId' => (int) $ConvID, + 'subject' => $Subject.($ForwardedID > 0 ? ' (Forwarded to '.$ForwardedName.')':''), + 'sticky' => $Sticky == 1, + 'messages' => $JsonMessages + ) + ) + ); +?> diff --git a/sections/ajax/index.php b/sections/ajax/index.php new file mode 100644 index 00000000..26af8171 --- /dev/null +++ b/sections/ajax/index.php @@ -0,0 +1,88 @@ + 'failure')); +} + +?> diff --git a/sections/ajax/info.php b/sections/ajax/info.php new file mode 100644 index 00000000..93cc9678 --- /dev/null +++ b/sections/ajax/info.php @@ -0,0 +1,37 @@ + 'success', + 'response' => array( + 'username' => $LoggedUser['Username'], + 'id' => $LoggedUser['ID'], + 'authkey'=> $LoggedUser['AuthKey'], + 'passkey'=> $LoggedUser['torrent_pass'], + 'userstats' => array( + 'uploaded' => (int) $LoggedUser['BytesUploaded'], + 'downloaded' => (int) $LoggedUser['BytesDownloaded'], + 'ratio' => (float) $Ratio, + 'requiredratio' => (float) $LoggedUser['RequiredRatio'], + //'class' => $Class + 'class' => $ClassLevels[$LoggedUser['Class']]['Name'] + ), + ) + ) +); + +?> diff --git a/sections/ajax/loadavg.php b/sections/ajax/loadavg.php new file mode 100644 index 00000000..ed872cb1 --- /dev/null +++ b/sections/ajax/loadavg.php @@ -0,0 +1,15 @@ + 'success', + 'response' => array( + 'loadAverage' => sys_getloadavg() + ) + ) + ); + +?> diff --git a/sections/ajax/notifications.php b/sections/ajax/notifications.php new file mode 100644 index 00000000..3274a83e --- /dev/null +++ b/sections/ajax/notifications.php @@ -0,0 +1,144 @@ + 'failure' + ) + ); + die(); +} + +define('NOTIFICATIONS_PER_PAGE', 50); +list($Page,$Limit) = page_limit(NOTIFICATIONS_PER_PAGE); + +$TokenTorrents = $Cache->get_value('users_tokens_'.$UserID); +if (empty($TokenTorrents)) { + $DB->query("SELECT TorrentID FROM users_freeleeches WHERE UserID=$UserID AND Expired=FALSE"); + $TokenTorrents = $DB->collect('TorrentID'); + $Cache->cache_value('users_tokens_'.$UserID, $TokenTorrents); +} + +$Results = $DB->query("SELECT SQL_CALC_FOUND_ROWS + t.ID, + g.ID, + g.Name, + g.CategoryID, + g.TagList, + t.Size, + t.FileCount, + t.Format, + t.Encoding, + t.Media, + t.Scene, + t.RemasterYear, + g.Year, + t.RemasterYear, + t.RemasterTitle, + t.Snatched, + t.Seeders, + t.Leechers, + t.Time, + t.HasLog, + t.HasCue, + t.LogScore, + t.FreeTorrent, + tln.TorrentID AS LogInDB, + unt.UnRead, + unt.FilterID, + unf.Label + FROM users_notify_torrents AS unt + JOIN torrents AS t ON t.ID=unt.TorrentID + JOIN torrents_group AS g ON g.ID = t.GroupID + LEFT JOIN users_notify_filters AS unf ON unf.ID=unt.FilterID + LEFT JOIN torrents_logs_new AS tln ON tln.TorrentID=t.ID + WHERE unt.UserID='$LoggedUser[ID]' + GROUP BY t.ID + ORDER BY t.ID DESC LIMIT $Limit"); +$DB->query('SELECT FOUND_ROWS()'); +list($TorrentCount) = $DB->next_record(); + +// Only clear the alert if they've specified to. +if (isset($_GET['clear']) && $_GET['clear'] == "1") { + //Clear before header but after query so as to not have the alert bar on this page load + $DB->query("UPDATE users_notify_torrents SET UnRead='0' WHERE UserID=".$LoggedUser['ID']); + $Cache->delete_value('notifications_new_'.$LoggedUser['ID']); +} + +$DB->set_query_id($Results); + +$Pages=get_pages($Page,$TorrentCount,NOTIFICATIONS_PER_PAGE,9); + +$JsonNotifications = array(); +$NumNew = 0; + +$FilterGroups = array(); +while($Result = $DB->next_record()) { + if(!$Result['FilterID']) { + $Result['FilterID'] = 0; + } + if(!isset($FilterGroups[$Result['FilterID']])) { + $FilterGroups[$Result['FilterID']] = array(); + $FilterGroups[$Result['FilterID']]['FilterLabel'] = ($Result['FilterID'] && !empty($Result['Label']) ? $Result['Label'] : 'unknown filter'.($Result['FilterID']?' ['.$Result['FilterID'].']':'')); + } + array_push($FilterGroups[$Result['FilterID']], $Result); +} +unset($Result); + +foreach($FilterGroups as $ID => $FilterResults) { + unset($FilterResults['FilterLabel']); + foreach($FilterResults as $Result) { + list($TorrentID, $GroupID, $GroupName, $GroupCategoryID, $TorrentTags, $Size, $FileCount, $Format, $Encoding, + $Media, $Scene, $RemasterYear, $GroupYear, $RemasterYear, $RemasterTitle, $Snatched, $Seeders, + $Leechers, $NotificationTime, $HasLog, $HasCue, $LogScore, $FreeTorrent, $LogInDB, $UnRead) = $Result; + + $Artists = get_artist($GroupID); + + if ($Unread) $NumNew++; + + $JsonNotifications[] = array( + 'torrentId' => (int) $TorrentID, + 'groupId' => (int) $GroupID, + 'groupName' => $GroupName, + 'groupCategoryId' => (int) $GroupCategoryID, + 'torrentTags' => $TorrentTags, + 'size' => (float) $Size, + 'fileCount' => (int) $FileCount, + 'format' => $Format, + 'encoding' => $Encoding, + 'media' => $Media, + 'scene' => $Scene == 1, + 'groupYear' => (int) $GroupYear, + 'remasterYear' => (int) $RemasterYear, + 'remasterTitle' => $RemasterTitle, + 'snatched' => (int) $Snatched, + 'seeders' => (int) $Seeders, + 'leechers' => (int) $Leechers, + 'notificationTime' => $NotificationTime, + 'hasLog' => $HasLog == 1, + 'hasCue' => $HasCue == 1, + 'logScore' => (float) $LogScore, + 'freeTorrent' => $FreeTorrent == 1, + 'logInDb' => $LogInDB, + 'unread' => $UnRead == 1 + ); + } +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'currentPages' => intval($Page), + 'pages' => ceil($TorrentCount/NOTIFICATIONS_PER_PAGE), + 'numNew' => $NumNew, + 'results' => $JsonNotifications + ) + ) + ); + +?> diff --git a/sections/ajax/preview.php b/sections/ajax/preview.php new file mode 100644 index 00000000..085a1e98 --- /dev/null +++ b/sections/ajax/preview.php @@ -0,0 +1,13 @@ +full_format($_POST['AdminComment']); +} else { + $Content = $_REQUEST['body']; // Don't use URL decode. + echo $Text->full_format($Content); +} +?> diff --git a/sections/ajax/request.php b/sections/ajax/request.php new file mode 100644 index 00000000..37810378 --- /dev/null +++ b/sections/ajax/request.php @@ -0,0 +1,256 @@ + 'failure' + ) + ); + die(); +} + +$RequestID = $_GET['id']; + +//First things first, lets get the data for the request. + +$Request = get_requests(array($RequestID)); +$Request = $Request['matches'][$RequestID]; +if(empty($Request)) { + print + json_encode( + array( + 'status' => 'failure' + ) + ); + die(); +} + +list($RequestID, $RequestorID, $RequestorName, $TimeAdded, $LastVote, $CategoryID, $Title, $Year, $Image, $Description, $CatalogueNumber, $ReleaseType, + $BitrateList, $FormatList, $MediaList, $LogCue, $FillerID, $FillerName, $TorrentID, $TimeFilled) = $Request; + +//Convenience variables +$IsFilled = !empty($TorrentID); +$CanVote = (empty($TorrentID) && check_perms('site_vote')); + +if($CategoryID == 0) { + $CategoryName = "Unknown"; +} else { + $CategoryName = $Categories[$CategoryID - 1]; +} + +//Do we need to get artists? +if($CategoryName == "Music") { + $ArtistForm = get_request_artists($RequestID); + $ArtistName = display_artists($ArtistForm, false, true); + $ArtistLink = display_artists($ArtistForm, true, true); + + if($IsFilled) { + $DisplayLink = $ArtistLink."".$Title." [".$Year."]"; + } else { + $DisplayLink = $ArtistLink.$Title." [".$Year."]"; + } + $FullName = $ArtistName.$Title." [".$Year."]"; + + if($BitrateList != "") { + $BitrateString = implode(", ", explode("|", $BitrateList)); + $FormatString = implode(", ", explode("|", $FormatList)); + $MediaString = implode(", ", explode("|", $MediaList)); + } else { + $BitrateString = "Unknown, please read the description."; + $FormatString = "Unknown, please read the description."; + $MediaString = "Unknown, please read the description."; + } + + if(empty($ReleaseType)) { + $ReleaseName = "Unknown"; + } else { + $ReleaseName = $ReleaseTypes[$ReleaseType]; + } + +} else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + $FullName = $Title." [".$Year."]"; + $DisplayLink = $Title." [".$Year."]"; +} else { + $FullName = $Title; + $DisplayLink = $Title; +} + +//Votes time +$RequestVotes = get_votes_array($RequestID); +$VoteCount = count($RequestVotes['Voters']); +$ProjectCanEdit = (check_perms('project_team') && !$IsFilled && (($CategoryID == 0) || ($CategoryName == "Music" && $Year == 0))); +$UserCanEdit = (!$IsFilled && $LoggedUser['ID'] == $RequestorID && $VoteCount < 2); +$CanEdit = ($UserCanEdit || $ProjectCanEdit || check_perms('site_moderate_requests')); + +$JsonMusicInfo = array(); +if ($CategoryName == "Music") { + $JsonMusicInfo = array( + /*'composers' => $ArtistForm[4] != null ? $ArtistForm[4] : array(), + 'dj' => $ArtistForm[6] != null ? $ArtistForm[6] : array(), + 'artists' => $ArtistForm[1] != null ? $ArtistForm[1] : array(), + 'with' => $ArtistForm[2] != null ? $ArtistForm[2] : array(), + 'conductor' => $ArtistForm[5] != null ? $ArtistForm[5] : array(), + 'remixedBy' => $ArtistForm[3] != null ? $ArtistForm[3] : array()*/ + 'composers' => $ArtistForm[4] == null ? array() : pullmediainfo($ArtistForm[4]), + 'dj' => $ArtistForm[6] == null ? array() : pullmediainfo($ArtistForm[6]), + 'artists' => $ArtistForm[1] == null ? array() : pullmediainfo($ArtistForm[1]), + 'with' => $ArtistForm[2] == null ? array() : pullmediainfo($ArtistForm[2]), + 'conductor' => $ArtistForm[5] == null ? array() : pullmediainfo($ArtistForm[5]), + 'remixedBy' => $ArtistForm[3] == null ? array() : pullmediainfo($ArtistForm[3]), + 'producer' => $ArtistForm[7] == null ? array() : pullmediainfo($ArtistForm[7]) + ); +} + +$JsonTopContributors = array(); +$VoteMax = ($VoteCount < 5 ? $VoteCount : 5); +for($i = 0; $i < $VoteMax; $i++) { + $User = array_shift($RequestVotes['Voters']); + $JsonTopContributors[] = array( + 'userId' => (int) $User['UserID'], + 'userName' => $User['Username'], + 'bounty' => (int) $User['Bounty'] + ); +} +reset($RequestVotes['Voters']); + +$Results = $Cache->get_value('request_comments_'.$RequestID); +if($Results === false) { + $DB->query("SELECT + COUNT(c.ID) + FROM requests_comments as c + WHERE c.RequestID = '$RequestID'"); + list($Results) = $DB->next_record(); + $Cache->cache_value('request_comments_'.$RequestID, $Results, 0); +} + +list($Page,$Limit) = page_limit(TORRENT_COMMENTS_PER_PAGE,$Results); + +//Get the cache catalogue +$CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE*$Page-TORRENT_COMMENTS_PER_PAGE)/THREAD_CATALOGUE); +$CatalogueLimit=$CatalogueID*THREAD_CATALOGUE . ', ' . THREAD_CATALOGUE; + +//---------- Get some data to start processing + +// Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page +$Catalogue = $Cache->get_value('request_comments_'.$RequestID.'_catalogue_'.$CatalogueID); +if($Catalogue === false) { + $DB->query("SELECT + c.ID, + c.AuthorID, + c.AddedTime, + c.Body, + c.EditedUserID, + c.EditedTime, + u.Username + FROM requests_comments as c + LEFT JOIN users_main AS u ON u.ID=c.EditedUserID + WHERE c.RequestID = '$RequestID' + ORDER BY c.ID + LIMIT $CatalogueLimit"); + $Catalogue = $DB->to_array(false,MYSQLI_ASSOC); + $Cache->cache_value('request_comments_'.$RequestID.'_catalogue_'.$CatalogueID, $Catalogue, 0); +} + +//This is a hybrid to reduce the catalogue down to the page elements: We use the page limit % catalogue +$Thread = array_slice($Catalogue,((TORRENT_COMMENTS_PER_PAGE*$Page-TORRENT_COMMENTS_PER_PAGE)%THREAD_CATALOGUE),TORRENT_COMMENTS_PER_PAGE,true); + +$JsonRequestComments = array(); +foreach($Thread as $Key => $Post){ + list($PostID, $AuthorID, $AddedTime, $Body, $EditedUserID, $EditedTime, $EditedUsername) = array_values($Post); + list($AuthorID, $Username, $PermissionID, $Paranoia, $Artist, $Donor, $Warned, $Avatar, $Enabled, $UserTitle) = array_values(user_info($AuthorID)); + $JsonRequestComments[] = array( + 'postId' => (int) $PostID, + 'authorId' => (int) $AuthorID, + 'name' => $Username, + 'donor' => $Donor == 1, + 'warned' => ($Warned!='0000-00-00 00:00:00'), + 'enabled' => ($Enabled == 2 ? false : true), + 'class' => make_class_string($PermissionID), + 'addedTime' => $AddedTime, + 'avatar' => $Avatar, + 'comment' => $Text->full_format($Body), + 'editedUserId' => (int) $EditedUserID, + 'editedUsername' => $EditedUsername, + 'editedTime' => $EditedTime + ); +} + +$JsonTags = array(); +foreach($Request['Tags'] as $Tag) { + $JsonTags[] = $Tag; +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'requestId' => (int) $RequestID, + 'requestorId' => (int) $RequestorID, + 'requestorName' => $RequestorName, + 'requestTax' => $RequestTax, + 'timeAdded' => $TimeAdded, + 'canEdit' => $CanEdit, + 'canVote' => $CanVote, + 'minimumVote' => $MinimumVote, + 'voteCount' => $VoteCount, + 'lastVote' => $LastVote, + 'topContributors' => $JsonTopContributors, + 'totalBounty' => (int) $RequestVotes['TotalBounty'], + 'categoryId' => (int) $CategoryID, + 'categoryName' => $CategoryName, + 'title' => $Title, + 'year' => (int) $Year, + 'image' => $Image, + 'description' => $Text->full_format($Description), + 'musicInfo' => $JsonMusicInfo, + 'catalogueNumber' => $CatalogueNumber, + 'releaseType' => (int) $ReleaseType, + 'releaseName' => $ReleaseName, + 'bitrateList' => $BitrateList, + 'formatList' => $FormatList, + 'mediaList' => $MediaList, + 'logCue' => $LogCue, + 'isFilled' => $IsFilled, + 'fillerId' => (int) $FillerID, + 'fillerName' => $FillerName, + 'torrentId' => (int) $TorrentID, + 'timeFilled' => $TimeFilled, + 'tags' => $JsonTags, + 'comments' => $JsonRequestComments, + 'commentPage' => (int) $Page, + 'commentPages' => (int) ceil($Results / TORRENT_COMMENTS_PER_PAGE) + ) + ) + ); + +function pullmediainfo($Array) { + $NewArray = array(); + foreach ($Array as $Item) { + $NewArray[] = array( + 'id' => (int) $Item['id'], + 'name' => $Item['name'] + ); + } + return $NewArray; +} +?> diff --git a/sections/ajax/requests.php b/sections/ajax/requests.php new file mode 100644 index 00000000..950c423b --- /dev/null +++ b/sections/ajax/requests.php @@ -0,0 +1,383 @@ +set_filter('visible', array(1)); + } +} else { + switch($_GET['type']) { + case 'created': + $Title = 'My requests'; + $SS->set_filter('userid', array($LoggedUser['ID'])); + break; + case 'voted': + if(!empty($_GET['userid'])) { + if(is_number($_GET['userid'])) { + if (!check_paranoia('requestsvoted_list', $UserInfo['Paranoia'], $Perms['Class'], $_GET['userid'])) { + print json_encode(array('status' => 'failure')); + die(); + } + $Title = "Requests voted for by ".$UserInfo['Username']; + $SS->set_filter('voter', array($_GET['userid'])); + } else { + print json_encode(array('status' => 'failure')); + die(); + } + } else { + $Title = "Requests I've voted on"; + $SS->set_filter('voter', array($LoggedUser['ID'])); + } + break; + case 'filled': + if(empty($_GET['userid']) || !is_number($_GET['userid'])) { + print json_encode(array('status' => 'failure')); + die(); + } else { + if (!check_paranoia('requestsfilled_list', $UserInfo['Paranoia'], $Perms['Class'], $_GET['userid'])) { + print json_encode(array('status' => 'failure')); + die(); + } + $Title = "Requests filled by ".$UserInfo['Username']; + $SS->set_filter('fillerid', array($_GET['userid'])); + } + break; + case 'bookmarks': + $Title = 'Your bookmarked requests'; + $BookmarkView = true; + $SS->set_filter('bookmarker', array($LoggedUser['ID'])); + break; + default: + print json_encode(array('status' => 'failure')); + die(); + } +} + +if($Submitted && empty($_GET['show_filled'])) { + $SS->set_filter('torrentid', array(0)); +} + +if(!empty($_GET['search'])) { + $Words = explode(' ', $_GET['search']); + foreach($Words as $Key => &$Word) { + if($Word[0] == '!' && strlen($Word) > 2) { + if(strpos($Word,'!',1) === false) { + $Word = '!'.$SS->EscapeString(substr($Word,1)); + } else { + $Word = $SS->EscapeString($Word); + } + } elseif(strlen($Word) >= 2) { + $Word = $SS->EscapeString($Word); + } else { + unset($Words[$Key]); + } + } + if(!empty($Words)) { + $Queries[] = "@* ".implode(' ', $Words); + } +} + +if(!empty($_GET['tags'])){ + $Tags = explode(',', $_GET['tags']); + $TagNames = array(); + foreach ($Tags as $Tag) { + $Tag = sanitize_tag($Tag); + if(!empty($Tag)) { + $TagNames[] = $Tag; + } + } + $Tags = get_tags($TagNames); +} + +if(empty($_GET['tags_type']) && !empty($Tags)) { + $_GET['tags_type'] = '0'; + $SS->set_filter('tagid', array_keys($Tags)); +} elseif(!empty($Tags)) { + foreach(array_keys($Tags) as $Tag) { + $SS->set_filter('tagid', array($Tag)); + } +} else { + $_GET['tags_type'] = '1'; +} + +if(!empty($_GET['filter_cat'])) { + $Keys = array_keys($_GET['filter_cat']); + $SS->set_filter('categoryid', $Keys); +} + +if(!empty($_GET['releases'])) { + $ReleaseArray = $_GET['releases']; + if(count($ReleaseArray) != count($ReleaseTypes)) { + foreach($ReleaseArray as $Index => $Value) { + if(!is_number($Value)) { + print json_encode(array('status' => 'failure')); + die(); + } + } + + $SS->set_filter('releasetype', $ReleaseArray); + } +} + +if(!empty($_GET['formats'])) { + $FormatArray = $_GET['formats']; + if(count($FormatArray) != count($Formats)) { + $FormatNameArray = array(); + foreach($FormatArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Formats)) { + $FormatNameArray[$Index] = $Formats[$MasterIndex]; + } else { + //Hax + print json_encode(array('status' => 'failure')); + die(); + } + } + + $Queries[]='@formatlist '.implode(' | ', $FormatNameArray); + } +} + +if(!empty($_GET['media'])) { + $MediaArray = $_GET['media']; + if(count($MediaArray) != count($Media)) { + $MediaNameArray = array(); + foreach($MediaArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Media)) { + $MediaNameArray[$Index] = $Media[$MasterIndex]; + } else { + //Hax + print json_encode(array('status' => 'failure')); + die(); + } + } + + $Queries[]='@medialist '.implode(' | ', $MediaNameArray); + } +} + +if(!empty($_GET['bitrates'])) { + $BitrateArray = $_GET['bitrates']; + if(count($BitrateArray) != count($Bitrates)) { + $BitrateNameArray = array(); + foreach($BitrateArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Bitrates)) { + $BitrateNameArray[$Index] = $SS->EscapeString($Bitrates[$MasterIndex]); + } else { + //Hax + print json_encode(array('status' => 'failure')); + die(); + } + } + + $Queries[]='@bitratelist '.implode(' | ', $BitrateNameArray); + } +} + +if(!empty($_GET['requestor']) && check_perms('site_see_old_requests')) { + if(is_number($_GET['requestor'])) { + $SS->set_filter('userid', array($_GET['requestor'])); + } else { + print json_encode(array('status' => 'failure')); + die(); + } +} + +if(isset($_GET['year'])) { + if(is_number($_GET['year']) || $_GET['year'] == 0) { + $SS->set_filter('year', array($_GET['year'])); + } else { + print json_encode(array('status' => 'failure')); + die(); + } +} + +if(!empty($_GET['page']) && is_number($_GET['page'])) { + $Page = min($_GET['page'], 50000/REQUESTS_PER_PAGE); + $SS->limit(($Page - 1) * REQUESTS_PER_PAGE, REQUESTS_PER_PAGE, 50000); +} else { + $Page = 1; + $SS->limit(0, REQUESTS_PER_PAGE, 50000); +} + +if(empty($_GET['order'])) { + $CurrentOrder = 'created'; + $CurrentSort = 'desc'; + $Way = SPH_SORT_ATTR_DESC; + $NewSort = 'asc'; +} else { + if(in_array($_GET['order'], $OrderWays)) { + $CurrentOrder = $_GET['order']; + if($_GET['sort'] == 'asc' || $_GET['sort'] == 'desc') { + $CurrentSort = $_GET['sort']; + $Way = ($CurrentSort == 'asc' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC); + $NewSort = ($_GET['sort'] == 'asc' ? 'desc' : 'asc'); + } else { + print json_encode(array('status' => 'failure')); + die(); + } + } else { + print json_encode(array('status' => 'failure')); + die(); + } +} + +switch($CurrentOrder) { + case 'votes' : + $OrderBy = "Votes"; + break; + case 'bounty' : + $OrderBy = "Bounty"; + break; + case 'created' : + $OrderBy = "TimeAdded"; + break; + case 'lastvote' : + $OrderBy = "LastVote"; + break; + case 'filled' : + $OrderBy = "TimeFilled"; + break; + case 'year' : + $OrderBy = "Year"; + break; + default : + $OrderBy = "TimeAdded"; + break; +} +//print($Way); print($OrderBy); die(); +$SS->SetSortMode($Way, $OrderBy); + +if(count($Queries) > 0) { + $Query = implode(' ',$Queries); +} else { + $Query=''; +} + +$SS->set_index('requests requests_delta'); +$SphinxResults = $SS->search($Query, '', 0, array(), '', ''); +$NumResults = $SS->TotalResults; +//We don't use sphinxapi's default cache searcher, we use our own functions + +if(!empty($SphinxResults['notfound'])) { + $SQLResults = get_requests($SphinxResults['notfound']); + if(is_array($SQLResults['notfound'])) { + //Something wasn't found in the db, remove it from results + reset($SQLResults['notfound']); + foreach($SQLResults['notfound'] as $ID) { + unset($SQLResults['matches'][$ID]); + unset($SphinxResults['matches'][$ID]); + } + } + + // Merge SQL results with memcached results + foreach($SQLResults['matches'] as $ID => $SQLResult) { + $SphinxResults['matches'][$ID] = $SQLResult; + + //$Requests['matches'][$ID] = array_merge($Requests['matches'][$ID], $SQLResult); + //We ksort because depending on the filter modes, we're given our data in an unpredictable order + //ksort($Requests['matches'][$ID]); + } +} + +$Requests = $SphinxResults['matches']; + +if ($NumResults == 0) { + print json_encode( + array( + 'status' => 'success', + 'response' => array( + 'currentPage' => 1, + 'pages' => 1, + 'results' => array() + ) + ) + ); + die(); +} else { + $JsonResults = array(); + $TimeCompare = 1267643718; // Requests v2 was implemented 2010-03-03 20:15:18 + foreach ($Requests as $RequestID => $Request) { + + //list($BitrateList, $CatalogueNumber, $CategoryID, $Description, $FillerID, $FormatList, $RequestID, $Image, $LogCue, $MediaList, $ReleaseType, + // $Tags, $TimeAdded, $TimeFilled, $Title, $TorrentID, $RequestorID, $RequestorName, $Year, $RequestID, $Categoryid, $FillerID, $LastVote, + // $ReleaseType, $TagIDs, $TimeAdded, $TimeFilled, $TorrentID, $RequestorID, $Voters) = array_values($Request); + + list($RequestID, $RequestorID, $RequestorName, $TimeAdded, $LastVote, $CategoryID, $Title, $Year, $Image, $Description, $CatalogueNumber, + $ReleaseType, $BitrateList, $FormatList, $MediaList, $LogCue, $FillerID, $FillerName, $TorrentID, $TimeFilled) = $Request; + + $RequestVotes = get_votes_array($RequestID); + + $VoteCount = count($RequestVotes['Voters']); + + if($CategoryID == 0) { + $CategoryName = "Unknown"; + } else { + $CategoryName = $Categories[$CategoryID - 1]; + } + + $JsonArtists = array(); + if($CategoryName == "Music") { + $ArtistForm = get_request_artists($RequestID); + $JsonArtists = array_values($ArtistForm); + } + + $Tags = $Request['Tags']; + + $JsonResults[] = array( + 'requestId' => (int) $RequestID, + 'requestorId' => (int) $RequestorID, + 'requestorName' => $RequestorName, + 'timeAdded' => $TimeAdded, + 'lastVote' => $LastVote, + 'voteCount' => $VoteCount, + 'bounty' => $RequestVotes['TotalBounty'], + 'categoryId' => (int) $CategoryID, + 'categoryName' => $CategoryName, + 'artists' => $JsonArtists, + 'title' => $Title, + 'year' => (int) $Year, + 'image' => $Image, + 'description' => $Description, + 'catalogueNumber' => $CatalogueNumber, + 'releaseType' => $ReleaseType, + 'bitrateList' => $BitrateList, + 'formatList' => $FormatList, + 'mediaList' => $MediaList, + 'logCue' => $LogCue, + 'isFilled' => ($TorrentID > 0), + 'fillerId' => (int) $FillerID, + 'fillerName' => $FillerName == 0 ? "" : $FillerName, + 'torrentId' => (int) $TorrentID, + 'timeFilled' => $TimeFilled == 0 ? "" : $TimeFilled + ); + } + + print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'currentPage' => intval($Page), + 'pages' => ceil($NumResults/REQUESTS_PER_PAGE), + 'results' => $JsonResults + ) + ) + ); +} +?> diff --git a/sections/ajax/stats.php b/sections/ajax/stats.php new file mode 100644 index 00000000..bb3da2fd --- /dev/null +++ b/sections/ajax/stats.php @@ -0,0 +1,7 @@ +begin_transaction('stats_links'); + $Cache->update_row(false, array($_GET['stat'] => '+1')); + $Cache->commit_transaction(0); +} +?> diff --git a/sections/ajax/subscriptions.php b/sections/ajax/subscriptions.php new file mode 100644 index 00000000..061df3a3 --- /dev/null +++ b/sections/ajax/subscriptions.php @@ -0,0 +1,122 @@ + 'failure' + ) + ); + die(); +} + +include(SERVER_ROOT.'/classes/class_text.php'); // Text formatting class +$Text = new TEXT; + +if (isset($LoggedUser['PostsPerPage'])) { + $PerPage = $LoggedUser['PostsPerPage']; +} else { + $PerPage = POSTS_PER_PAGE; +} +list($Page,$Limit) = page_limit($PerPage); + +if($LoggedUser['CustomForums']) { + unset($LoggedUser['CustomForums']['']); + $RestrictedForums = implode("','", array_keys($LoggedUser['CustomForums'], 0)); + $PermittedForums = implode("','", array_keys($LoggedUser['CustomForums'], 1)); +} + +$ShowUnread = (!isset($_GET['showunread']) && !isset($HeavyInfo['SubscriptionsUnread']) || isset($HeavyInfo['SubscriptionsUnread']) && !!$HeavyInfo['SubscriptionsUnread'] || isset($_GET['showunread']) && !!$_GET['showunread']); +$ShowCollapsed = (!isset($_GET['collapse']) && !isset($HeavyInfo['SubscriptionsCollapse']) || isset($HeavyInfo['SubscriptionsCollapse']) && !!$HeavyInfo['SubscriptionsCollapse'] || isset($_GET['collapse']) && !!$_GET['collapse']); +$sql = 'SELECT + SQL_CALC_FOUND_ROWS + MAX(p.ID) AS ID + FROM forums_posts AS p + LEFT JOIN forums_topics AS t ON t.ID = p.TopicID + JOIN users_subscriptions AS s ON s.TopicID = t.ID + LEFT JOIN forums AS f ON f.ID = t.ForumID + LEFT JOIN forums_last_read_topics AS l ON p.TopicID = l.TopicID AND l.UserID = s.UserID + WHERE s.UserID = '.$LoggedUser['ID'].' + AND p.ID <= IFNULL(l.PostID,t.LastPostID) + AND ((f.MinClassRead <= '.$LoggedUser['Class']; +if(!empty($RestrictedForums)) { + $sql.=' AND f.ID NOT IN (\''.$RestrictedForums.'\')'; +} +$sql .= ')'; +if(!empty($PermittedForums)) { + $sql.=' OR f.ID IN (\''.$PermittedForums.'\')'; +} +$sql .= ')'; +if($ShowUnread) { + $sql .= ' + AND IF(l.PostID IS NULL OR (t.IsLocked = \'1\' && t.IsSticky = \'0\'), t.LastPostID, l.PostID) < t.LastPostID'; +} +$sql .= ' + GROUP BY t.ID + ORDER BY t.LastPostID DESC + LIMIT '.$Limit; +$PostIDs = $DB->query($sql); +$DB->query('SELECT FOUND_ROWS()'); +list($NumResults) = $DB->next_record(); + +if($NumResults > $PerPage*($Page-1)) { + $DB->set_query_id($PostIDs); + $PostIDs = $DB->collect('ID'); + $sql = 'SELECT + f.ID AS ForumID, + f.Name AS ForumName, + p.TopicID, + t.Title, + p.Body, + t.LastPostID, + t.IsLocked, + t.IsSticky, + p.ID, + um.ID, + um.Username, + ui.Avatar, + p.EditedUserID, + p.EditedTime, + ed.Username AS EditedUsername + FROM forums_posts AS p + LEFT JOIN forums_topics AS t ON t.ID = p.TopicID + LEFT JOIN forums AS f ON f.ID = t.ForumID + LEFT JOIN users_main AS um ON um.ID = p.AuthorID + LEFT JOIN users_info AS ui ON ui.UserID = um.ID + LEFT JOIN users_main AS ed ON ed.ID = um.ID + WHERE p.ID IN ('.implode(',',$PostIDs).') + ORDER BY f.Name ASC, t.LastPostID DESC'; + $DB->query($sql); +} + +$JsonPosts = array(); +while(list($ForumID, $ForumName, $TopicID, $ThreadTitle, $Body, $LastPostID, $Locked, $Sticky, $PostID, $AuthorID, $AuthorName, $AuthorAvatar, $EditedUserID, $EditedTime, $EditedUsername) = $DB->next_record()){ + $JsonPost = array( + 'forumId' => (int) $ForumID, + 'forumName' => $ForumName, + 'threadId' => (int) $TopicID, + 'threadTitle' => $ThreadTitle, + 'postId' => (int) $PostID, + 'lastPostId' => (int) $LastPostID, + 'locked' => $Locked == 1, + 'new' => ($PostID<$LastPostID && !$Locked) + ); + $JsonPosts[] = $JsonPost; +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'threads' => $JsonPosts + ) + ) + ); +?> diff --git a/sections/ajax/top10/index.php b/sections/ajax/top10/index.php new file mode 100644 index 00000000..49ade612 --- /dev/null +++ b/sections/ajax/top10/index.php @@ -0,0 +1,29 @@ + 'failure')); + die(); +} + + +if(empty($_GET['type']) || $_GET['type'] == 'torrents') { + include(SERVER_ROOT.'/sections/ajax/top10/torrents.php'); +} else { + switch($_GET['type']) { + case 'users' : + include(SERVER_ROOT.'/sections/ajax/top10/users.php'); + break; + case 'tags' : + include(SERVER_ROOT.'/sections/ajax/top10/tags.php'); + break; + case 'history' : + include(SERVER_ROOT.'/sections/ajax/top10/history.php'); + break; + default : + print json_encode(array('status' => 'failure')); + break; + } +} +?> diff --git a/sections/ajax/top10/tags.php b/sections/ajax/top10/tags.php new file mode 100644 index 00000000..20e3392c --- /dev/null +++ b/sections/ajax/top10/tags.php @@ -0,0 +1,106 @@ + 'failure')); + die(); + } +} else { + $Details = 'all'; +} + +// defaults to 10 (duh) +$Limit = isset($_GET['limit']) ? intval($_GET['limit']) : 10; +$Limit = in_array($Limit, array(10, 100, 250)) ? $Limit : 10; +$OuterResults = array(); + +if ($Details == 'all' || $Details == 'ut') { + if (!$TopUsedTags = $Cache->get_value('topusedtag_'.$Limit)) { + $DB->query("SELECT + t.ID, + t.Name, + COUNT(tt.GroupID) AS Uses, + SUM(tt.PositiveVotes-1) AS PosVotes, + SUM(tt.NegativeVotes-1) AS NegVotes + FROM tags AS t + JOIN torrents_tags AS tt ON tt.TagID=t.ID + GROUP BY tt.TagID + ORDER BY Uses DESC + LIMIT $Limit"); + $TopUsedTags = $DB->to_array(); + $Cache->cache_value('topusedtag_'.$Limit,$TopUsedTags,3600*12); + } + + $OuterResults[] = generate_tag_json('Most Used Torrent Tags', 'ut', $TopUsedTags, $Limit); +} + +if ($Details == 'all' || $Details == 'ur') { + if (!$TopRequestTags = $Cache->get_value('toprequesttag_'.$Limit)) { + $DB->query("SELECT + t.ID, + t.Name, + COUNT(r.RequestID) AS Uses, + '','' + FROM tags AS t + JOIN requests_tags AS r ON r.TagID=t.ID + GROUP BY r.TagID + ORDER BY Uses DESC + LIMIT $Limit"); + $TopRequestTags = $DB->to_array(); + $Cache->cache_value('toprequesttag_'.$Limit,$TopRequestTags,3600*12); + } + + $OuterResults[] = generate_tag_json('Most Used Request Tags', 'ur', $TopRequestTags, $Limit); +} + +if ($Details == 'all' || $Details == 'v') { + if (!$TopVotedTags = $Cache->get_value('topvotedtag_'.$Limit)) { + $DB->query("SELECT + t.ID, + t.Name, + COUNT(tt.GroupID) AS Uses, + SUM(tt.PositiveVotes-1) AS PosVotes, + SUM(tt.NegativeVotes-1) AS NegVotes + FROM tags AS t + JOIN torrents_tags AS tt ON tt.TagID=t.ID + GROUP BY tt.TagID + ORDER BY PosVotes DESC + LIMIT $Limit"); + $TopVotedTags = $DB->to_array(); + $Cache->cache_value('topvotedtag_'.$Limit,$TopVotedTags,3600*12); + } + + $OuterResults[] = generate_tag_json('Most Highly Voted Tags', 'v', $TopVotedTags, $Limit); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => $OuterResults + ) + ); + +function generate_tag_json($Caption, $Tag, $Details, $Limit) { + $results = array(); + foreach ($Details as $Detail) { + $results[] = array( + 'name' => $Detail['Name'], + 'uses' => (int) $Detail['Uses'], + 'posVotes' => (int) $Detail['PosVotes'], + 'negVotes' => (int) $Detail['NegVotes'] + ); + } + + return array( + 'caption' => $Caption, + 'tag' => $Tag, + 'limit' => (int) $Limit, + 'results' => $results + ); +} diff --git a/sections/ajax/top10/torrents.php b/sections/ajax/top10/torrents.php new file mode 100644 index 00000000..1fbe9857 --- /dev/null +++ b/sections/ajax/top10/torrents.php @@ -0,0 +1,194 @@ + 'failure')); + die(); + } +} else { + $Details = 'all'; +} + +// defaults to 10 (duh) +$Limit = isset($_GET['limit']) ? intval($_GET['limit']) : 10; +$Limit = in_array($Limit, array(10, 100, 250)) ? $Limit : 10; + +$WhereSum = (empty($Where)) ? '' : md5($Where); +$BaseQuery = "SELECT + t.ID, + g.ID, + g.Name, + g.CategoryID, + g.TagList, + t.Format, + t.Encoding, + t.Media, + t.Scene, + t.HasLog, + t.HasCue, + t.LogScore, + t.RemasterYear, + g.Year, + t.RemasterTitle, + t.Snatched, + t.Seeders, + t.Leechers, + ((t.Size * t.Snatched) + (t.Size * 0.5 * t.Leechers)) AS Data + FROM torrents AS t + LEFT JOIN torrents_group AS g ON g.ID = t.GroupID "; + +$OuterResults = array(); + +if($Details == 'all' || $Details == 'day') { + if (!$TopTorrentsActiveLastDay = $Cache->get_value('top10tor_day_'.$Limit.$WhereSum)) { + $DayAgo = time_minus(86400); + $Query = $BaseQuery.' WHERE t.Seeders>0 AND '; + if (!empty($Where)) { $Query .= $Where.' AND '; } + $Query .= " + t.Time>'$DayAgo' + ORDER BY (t.Seeders + t.Leechers) DESC + LIMIT $Limit;"; + $DB->query($Query); + $TopTorrentsActiveLastDay = $DB->to_array(); + $Cache->cache_value('top10tor_day_'.$Limit.$WhereSum,$TopTorrentsActiveLastDay,3600*2); + } + $OuterResults[] = generate_torrent_json('Most Active Torrents Uploaded in the Past Day', 'day', $TopTorrentsActiveLastDay, $Limit); +} +if($Details == 'all' || $Details == 'week') { + if (!$TopTorrentsActiveLastWeek = $Cache->get_value('top10tor_week_'.$Limit.$WhereSum)) { + $WeekAgo = time_minus(604800); + $Query = $BaseQuery.' WHERE '; + if (!empty($Where)) { $Query .= $Where.' AND '; } + $Query .= " + t.Time>'$WeekAgo' + ORDER BY (t.Seeders + t.Leechers) DESC + LIMIT $Limit;"; + $DB->query($Query); + $TopTorrentsActiveLastWeek = $DB->to_array(); + $Cache->cache_value('top10tor_week_'.$Limit.$WhereSum,$TopTorrentsActiveLastWeek,3600*6); + } + $OuterResults[] = generate_torrent_json('Most Active Torrents Uploaded in the Past Week', 'week', $TopTorrentsActiveLastWeek, $Limit); +} + +if($Details == 'all' || $Details == 'overall') { + if (!$TopTorrentsActiveAllTime = $Cache->get_value('top10tor_overall_'.$Limit.$WhereSum)) { + // IMPORTANT NOTE - we use WHERE t.Seeders>500 in order to speed up this query. You should remove it! + $Query = $BaseQuery; + if (!empty($Where)) { $Query .= ' WHERE '.$Where; } + elseif ($Details=='all') { $Query .= " WHERE t.Seeders>500 "; } + $Query .= " + ORDER BY (t.Seeders + t.Leechers) DESC + LIMIT $Limit;"; + $DB->query($Query); + $TopTorrentsActiveAllTime = $DB->to_array(); + $Cache->cache_value('top10tor_overall_'.$Limit.$WhereSum,$TopTorrentsActiveAllTime,3600*6); + } + $OuterResults[] = generate_torrent_json('Most Active Torrents of All Time', 'overall', $TopTorrentsActiveAllTime, $Limit); +} + +if(($Details == 'all' || $Details == 'snatched') && empty($Where)) { + if (!$TopTorrentsSnatched = $Cache->get_value('top10tor_snatched_'.$Limit.$WhereSum)) { + $Query = $BaseQuery; + $Query .= " + ORDER BY t.Snatched DESC + LIMIT $Limit;"; + $DB->query($Query); + $TopTorrentsSnatched = $DB->to_array(); + $Cache->cache_value('top10tor_snatched_'.$Limit.$WhereSum,$TopTorrentsSnatched,3600*6); + } + $OuterResults[] = generate_torrent_json('Most Snatched Torrents', 'snatched', $TopTorrentsSnatched, $Limit); +} + +if(($Details == 'all' || $Details == 'data') && empty($Where)) { + if (!$TopTorrentsTransferred = $Cache->get_value('top10tor_data_'.$Limit.$WhereSum)) { + // IMPORTANT NOTE - we use WHERE t.Snatched>100 in order to speed up this query. You should remove it! + $Query = $BaseQuery; + if ($Details=='all') { $Query .= " WHERE t.Snatched>100 "; } + $Query .= " + ORDER BY Data DESC + LIMIT $Limit;"; + $DB->query($Query); + $TopTorrentsTransferred = $DB->to_array(); + $Cache->cache_value('top10tor_data_'.$Limit.$WhereSum,$TopTorrentsTransferred,3600*6); + } + $OuterResults[] = generate_torrent_json('Most Data Transferred Torrents', 'data', $TopTorrentsTransferred, $Limit); +} + +if(($Details == 'all' || $Details == 'seeded') && empty($Where)) { + if (!$TopTorrentsSeeded = $Cache->get_value('top10tor_seeded_'.$Limit.$WhereSum)) { + $Query = $BaseQuery." + ORDER BY t.Seeders DESC + LIMIT $Limit;"; + $DB->query($Query); + $TopTorrentsSeeded = $DB->to_array(); + $Cache->cache_value('top10tor_seeded_'.$Limit.$WhereSum,$TopTorrentsSeeded,3600*6); + } + $OuterResults[] = generate_torrent_json('Best Seeded Torrents', 'seeded', $TopTorrentsSeeded, $Limit); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => $OuterResults + ) + ); + + +function generate_torrent_json($Caption, $Tag, $Details, $Limit) { + global $LoggedUser,$Categories; + $results = array(); + foreach ($Details as $Detail) { + list($TorrentID,$GroupID,$GroupName,$GroupCategoryID,$TorrentTags, + $Format,$Encoding,$Media,$Scene,$HasLog,$HasCue,$LogScore,$Year,$GroupYear, + $RemasterTitle,$Snatched,$Seeders,$Leechers,$Data) = $Detail; + + $Artist = display_artists(get_artist($GroupID), false, true); + $TruncArtist = substr($Artist, 0, strlen($Artist)-3); + + $TagList=array(); + + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=$TagName; + } + } + + // Append to the existing array. + $results[] = array( + 'torrentId' => (int) $TorrentID, + 'groupId' => (int) $GroupID, + 'artist' => $TruncArtist, + 'groupName' => $GroupName, + 'groupCategory' => (int) $GroupCategory, + 'groupYear' => (int) $GroupYear, + 'remasterTitle' => $RemasterTitle, + 'format' => $Format, + 'encoding' => $Encoding, + 'hasLog' => $HasLog == 1, + 'hasCue' => $HasCue == 1, + 'media' => $Media, + 'scene' => $Scene == 1, + 'year' => (int) $Year, + 'tags' => $TagList, + 'snatched' => (int) $Snatched, + 'seeders' => (int) $Seeders, + 'leechers' => (int) $Leechers, + 'data' => (int) $Data + ); + } + + return array( + 'caption' => $Caption, + 'tag' => $Tag, + 'limit' => (int) $Limit, + 'results' => $results + ); +} +?> diff --git a/sections/ajax/top10/users.php b/sections/ajax/top10/users.php new file mode 100644 index 00000000..0e2cb509 --- /dev/null +++ b/sections/ajax/top10/users.php @@ -0,0 +1,114 @@ + 'failure')); + die(); + } +} else { + $Details = 'all'; +} + +// defaults to 10 (duh) +$Limit = isset($_GET['limit']) ? intval($_GET['limit']) : 10; +$Limit = in_array($Limit, array(10,100,250)) ? $Limit : 10; + +$BaseQuery = "SELECT + u.ID, + u.Username, + ui.JoinDate, + u.Uploaded, + u.Downloaded, + ABS(u.Uploaded-524288000) / (".time()." - UNIX_TIMESTAMP(ui.JoinDate)) AS UpSpeed, + u.Downloaded / (".time()." - UNIX_TIMESTAMP(ui.JoinDate)) AS DownSpeed, + COUNT(t.ID) AS NumUploads + FROM users_main AS u + JOIN users_info AS ui ON ui.UserID = u.ID + LEFT JOIN torrents AS t ON t.UserID=u.ID + WHERE u.Enabled='1' + AND Uploaded>'". 5*1024*1024*1024 ."' + AND Downloaded>'". 5*1024*1024*1024 ."' + AND (Paranoia IS NULL OR (Paranoia NOT LIKE '%\"uploaded\"%' AND Paranoia NOT LIKE '%\"downloaded\"%')) + GROUP BY u.ID"; + +$OuterResults = array(); + +if($Details == 'all' || $Details == 'ul') { + if (!$TopUserUploads = $Cache->get_value('topuser_ul_'.$Limit)) { + $DB->query("$BaseQuery ORDER BY u.Uploaded DESC LIMIT $Limit;"); + $TopUserUploads = $DB->to_array(); + $Cache->cache_value('topuser_ul_'.$Limit,$TopUserUploads,3600*12); + } + $OuterResults[] = generate_user_json('Uploaders', 'ul', $TopUserUploads, $Limit); +} + +if($Details == 'all' || $Details == 'dl') { + if (!$TopUserDownloads = $Cache->get_value('topuser_dl_'.$Limit)) { + $DB->query("$BaseQuery ORDER BY u.Downloaded DESC LIMIT $Limit;"); + $TopUserDownloads = $DB->to_array(); + $Cache->cache_value('topuser_dl_'.$Limit,$TopUserDownloads,3600*12); + } + $OuterResults[] = generate_user_json('Downloaders', 'dl', $TopUserDownloads, $Limit); +} + +if($Details == 'all' || $Details == 'numul') { + if (!$TopUserNumUploads = $Cache->get_value('topuser_numul_'.$Limit)) { + $DB->query("$BaseQuery ORDER BY NumUploads DESC LIMIT $Limit;"); + $TopUserNumUploads = $DB->to_array(); + $Cache->cache_value('topuser_numul_'.$Limit,$TopUserNumUploads,3600*12); + } + $OuterResults[] = generate_user_json('Torrents Uploaded', 'numul', $TopUserNumUploads, $Limit); +} + +if($Details == 'all' || $Details == 'uls') { + if (!$TopUserUploadSpeed = $Cache->get_value('topuser_ulspeed_'.$Limit)) { + $DB->query("$BaseQuery ORDER BY UpSpeed DESC LIMIT $Limit;"); + $TopUserUploadSpeed = $DB->to_array(); + $Cache->cache_value('topuser_ulspeed_'.$Limit,$TopUserUploadSpeed,3600*12); + } + $OuterResults[] = generate_user_json('Fastest Uploaders', 'uls', $TopUserUploadSpeed, $Limit); +} + +if($Details == 'all' || $Details == 'dls') { + if (!$TopUserDownloadSpeed = $Cache->get_value('topuser_dlspeed_'.$Limit)) { + $DB->query("$BaseQuery ORDER BY DownSpeed DESC LIMIT $Limit;"); + $TopUserDownloadSpeed = $DB->to_array(); + $Cache->cache_value('topuser_dlspeed_'.$Limit,$TopUserDownloadSpeed,3600*12); + } + $OuterResults[] = generate_user_json('Fastest Downloaders', 'dls', $TopUserDownloadSpeed, $Limit); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => $OuterResults + ) + ); + +function generate_user_json($Caption, $Tag, $Details, $Limit) { + $results = array(); + foreach($Details as $Details) { + $results[] = array( + 'id' => (int) $Detail['ID'], + 'username' => $Detail['Username'], + 'uploaded' => (float) $Detail['Uploaded'], + 'upSpeed' => (float) $Detail['UpSpeed'], + 'downloaded' => (float) $Detail['Downloaded'], + 'downSpeed' => (float) $Detail['DownSpeed'], + 'numUploads' => (int) $Detail['NumUploads'], + 'joinDate' => $Detail['JoinDate'] + ); + } + return array( + 'caption' => $Caption, + 'tag' => $Tag, + 'limit' => (int) $Limit, + 'results' => $results + ); +} +?> diff --git a/sections/ajax/torrentgroup.php b/sections/ajax/torrentgroup.php new file mode 100644 index 00000000..b44b6588 --- /dev/null +++ b/sections/ajax/torrentgroup.php @@ -0,0 +1,72 @@ + $Text->full_format($TorrentDetails['WikiBody']), + 'wikiImage' => $TorrentDetails['WikiImage'], + 'id' => (int) $TorrentDetails['ID'], + 'name' => $TorrentDetails['Name'], + 'year' => (int) $TorrentDetails['Year'], + 'recordLabel' => $TorrentDetails['RecordLabel'], + 'catalogueNumber' => $TorrentDetails['CatalogueNumber'], + 'releaseType' => (int) $TorrentDetails['ReleaseType'], + 'categoryId' => (int) $TorrentDetails['CategoryID'], + 'time' => $TorrentDetails['Time'], + 'vanityHouse' => $TorrentDetails['VanityHouse'] == 1, + 'artists' => get_artist($GroupID), +); +$TorrentList = array(); +foreach ($TorrentCache[1] as $Torrent) { + $TorrentList[] = filter_by_key($Torrent, $TorrentAllowed); +} +$JsonTorrentList = array(); +foreach ($TorrentList as $Torrent) { + $JsonTorrentList[] = array( + 'id' => (int) $Torrent['ID'], + 'media' => $Torrent['Media'], + 'format' => $Torrent['Format'], + 'encoding' => $Torrent['Encoding'], + 'remastered' => $Torrent['Remastered'] == 1, + 'remasterYear' => (int) $Torrent['RemasterYear'], + 'remasterTitle' => $Torrent['RemasterTitle'], + 'remasterRecordLabel' => $Torrent['RemasterRecordLabel'], + 'remasterCatalogueNumber' => $Torrent['RemasterCatalogueNumber'], + 'scene' => $Torrent['Scene'] == 1, + 'hasLog' => $Torrent['HasLog'] == 1, + 'hasCue' => $Torrent['HasCue'] == 1, + 'logScore' => (int) $Torrent['LogScore'], + 'fileCount' => (int) $Torrent['FileCount'], + 'size' => (int) $Torrent['Size'], + 'seeders' => (int) $Torrent['Seeders'], + 'leechers' => (int) $Torrent['Leechers'], + 'snatched' => (int) $Torrent['Snatched'], + 'freeTorrent' => $Torrent['FreeTorrent'] == 1, + 'time' => $Torrent['Time'], + 'description' => $Torrent['Description'], + 'fileList' => $Torrent['FileList'], + 'filePath' => $Torrent['FilePath'], + 'userId' => (int) $Torrent['UserID'], + 'username' => $Torrent['Username'] + ); +} + +print json_encode(array('status' => 'success', 'response' => array('group' => $JsonTorrentDetails, 'torrents' => $JsonTorrentList))); diff --git a/sections/ajax/upload.php b/sections/ajax/upload.php new file mode 100644 index 00000000..d86e24a9 --- /dev/null +++ b/sections/ajax/upload.php @@ -0,0 +1,40 @@ +get_value('genre_tags'); +if(!$GenreTags){ + $DB->query('SELECT Name FROM tags WHERE TagType=\'genre\' ORDER BY Name'); + $GenreTags = $DB->collect('Name'); + $Cache->cache_value('genre_tags', $GenreTags, 3600*24); +} + +$UploadForm = $Categories[$_GET['categoryid']]; + +switch($UploadForm) { + case 'Music': + $TorrentForm->music_form($GenreTags); + break; + + case 'Audiobooks': + case 'Comedy': + $TorrentForm->audiobook_form(); + break; + + case 'Applications': + case 'Comics': + case 'E-Books': + case 'E-Learning Videos': + $TorrentForm->simple_form($_GET['categoryid']); + break; + default: + echo "Invalid action!"; +} + + + +?> diff --git a/sections/ajax/user.php b/sections/ajax/user.php new file mode 100644 index 00000000..4f0f5002 --- /dev/null +++ b/sections/ajax/user.php @@ -0,0 +1,293 @@ +query("SELECT + m.Username, + m.Email, + m.LastAccess, + m.IP, + p.Level AS Class, + m.Uploaded, + m.Downloaded, + m.RequiredRatio, + m.Enabled, + m.Paranoia, + m.Invites, + m.Title, + m.torrent_pass, + m.can_leech, + i.JoinDate, + i.Info, + i.Avatar, + i.Country, + i.Donor, + i.Warned, + COUNT(posts.id) AS ForumPosts, + i.Inviter, + i.DisableInvites, + inviter.username + FROM users_main AS m + JOIN users_info AS i ON i.UserID = m.ID + LEFT JOIN permissions AS p ON p.ID=m.PermissionID + LEFT JOIN users_main AS inviter ON i.Inviter = inviter.ID + LEFT JOIN forums_posts AS posts ON posts.AuthorID = m.ID + WHERE m.ID = $UserID GROUP BY AuthorID"); + +//TODO: Handle this more gracefully. +if ($DB->record_count() == 0) { // If user doesn't exist + die(); + //header("Location: log.php?search=User+".$UserID); +} + +list($Username, $Email, $LastAccess, $IP, $Class, $Uploaded, $Downloaded, $RequiredRatio, $Enabled, $Paranoia, $Invites, $CustomTitle, $torrent_pass, $DisableLeech, $JoinDate, $Info, $Avatar, $Country, $Donor, $Warned, $ForumPosts, $InviterID, $DisableInvites, $InviterName, $RatioWatchEnds, $RatioWatchDownload) = $DB->next_record(MYSQLI_NUM, array(9,11)); + +$Paranoia = unserialize($Paranoia); +if(!is_array($Paranoia)) { + $Paranoia = array(); +} +$ParanoiaLevel = 0; +foreach($Paranoia as $P) { + $ParanoiaLevel++; + if(strpos($P, '+')) { + $ParanoiaLevel++; + } +} + +// Raw time is better for JSON. +//$JoinedDate = time_diff($JoinDate); +//$LastAccess = time_diff($LastAccess); + +function check_paranoia_here($Setting) { + global $Paranoia, $Class, $UserID; + return check_paranoia($Setting, $Paranoia, $Class, $UserID); +} + +$Friend = false; +$DB->query("SELECT FriendID FROM friends WHERE UserID='$LoggedUser[ID]' AND FriendID='$UserID'"); +if($DB->record_count() != 0) { + $Friend = true; +} + +if (check_paranoia_here('requestsfilled_count') || check_paranoia_here('requestsfilled_bounty')) { + $DB->query("SELECT COUNT(DISTINCT r.ID), SUM(rv.Bounty) FROM requests AS r LEFT JOIN requests_votes AS rv ON r.ID=rv.RequestID WHERE r.FillerID = ".$UserID); + list($RequestsFilled, $TotalBounty) = $DB->next_record(); + $DB->query("SELECT COUNT(rv.RequestID), SUM(rv.Bounty) FROM requests_votes AS rv WHERE rv.UserID = ".$UserID); + list($RequestsVoted, $TotalSpent) = $DB->next_record(); + + $DB->query("SELECT COUNT(ID) FROM torrents WHERE UserID='$UserID'"); + list($Uploads) = $DB->next_record(); +} else { + $RequestsVoted = 0; + $TotalSpent = 0; +} +if(check_paranoia_here('uploads+')) { + $DB->query("SELECT COUNT(ID) FROM torrents WHERE UserID='$UserID'"); + list($Uploads) = $DB->next_record(); +} else { + $Uploads = null; +} + +if (check_paranoia_here('artistsadded')) { + $DB->query("SELECT COUNT(ta.ArtistID) FROM torrents_artists AS ta WHERE ta.UserID = ".$UserID); + list($ArtistsAdded) = $DB->next_record(); +} else { + $ArtistsAdded = 0; +} + +// Do the ranks. +include(SERVER_ROOT.'/classes/class_user_rank.php'); +$Rank = new USER_RANK; + +if (check_paranoia_here('uploaded')) { + $UploadedRank = $Rank->get_rank('uploaded', $Uploaded); +} else { + $UploadedRank = null; +} +if (check_paranoia_here('downloaded')) { + $DownloadedRank = $Rank->get_rank('downloaded', $Downloaded); +} else { + $DownloadedRank = null; +} +if (check_paranoia_here('uploads+')) { + $UploadsRank = $Rank->get_rank('uploads', $Uploads); +} else { + $UploadsRank = null; +} +if (check_paranoia_here('requestsfilled_count')) { + $RequestRank = $Rank->get_rank('requests', $RequestsFilled); +} else { + $RequestRank = null; +} +$PostRank = $Rank->get_rank('posts', $ForumPosts); +if (check_paranoia_here('requestsvoted_bounty')) { + $BountyRank = $Rank->get_rank('bounty', $TotalSpent); +} else { + $BountyRank = null; +} +if (check_paranoia_here('artistsadded')) { + $ArtistsRank = $Rank->get_rank('artists', $ArtistsAdded); +} else { + $ArtistsRank = null; +} + +if($Downloaded == 0) { + $Ratio = 1; +} elseif($Uploaded == 0) { + $Ratio = 0.5; +} else { + $Ratio = round($Uploaded/$Downloaded, 2); +} +if (check_paranoia_here(array('uploaded', 'downloaded', 'uploads+', 'requestsfilled_count', 'requestsvoted_bounty', 'artistsadded'))) { + $OverallRank = floor($Rank->overall_score($UploadedRank, $DownloadedRank, $UploadsRank, $RequestRank, $PostRank, $BountyRank, $ArtistsRank, $Ratio)); +} else { + $OverallRank = null; +} + +// Community section +if(check_paranoia_here(array('snatched', 'snatched+'))) { +$DB->query("SELECT COUNT(x.uid), COUNT(DISTINCT x.fid) FROM xbt_snatched AS x INNER JOIN torrents AS t ON t.ID=x.fid WHERE x.uid='$UserID'"); +list($Snatched, $UniqueSnatched) = $DB->next_record(); +} + +if (check_paranoia_here(array('torrentcomments', 'torrentcomments+'))) { + $DB->query("SELECT COUNT(ID) FROM torrents_comments WHERE AuthorID='$UserID'"); + list($NumComments) = $DB->next_record(); +} + +if (check_paranoia_here(array('collages', 'collages+'))) { + $DB->query("SELECT COUNT(ID) FROM collages WHERE Deleted='0' AND UserID='$UserID'"); + list($NumCollages) = $DB->next_record(); +} + +if (check_paranoia_here(array('collagecontribs', 'collagecontribs+'))) { + $DB->query("SELECT COUNT(DISTINCT CollageID) FROM collages_torrents AS ct JOIN collages ON CollageID = ID WHERE Deleted='0' AND ct.UserID='$UserID'"); + list($NumCollageContribs) = $DB->next_record(); +} + +if (check_paranoia_here(array('uniquegroups', 'uniquegroups+'))) { + $DB->query("SELECT COUNT(DISTINCT GroupID) FROM torrents WHERE UserID = '$UserID'"); + list($UniqueGroups) = $DB->next_record(); +} + +if (check_paranoia_here(array('perfectflacs', 'perfectflacs+'))) { + $DB->query("SELECT COUNT(ID) FROM torrents WHERE ((LogScore = 100 AND Format = 'FLAC') OR (Media = 'Vinyl' AND Format = 'FLAC') OR (Media = 'WEB' AND Format = 'FLAC') OR (Media = 'DVD' AND Format = 'FLAC') OR (Media = 'Soundboard' AND Format = 'FLAC') OR (Media = 'Cassette' AND Format = 'FLAC') OR (Media = 'SACD' AND Format = 'FLAC') OR (Media = 'Blu-ray' AND Format = 'FLAC') OR (Media = 'DAT' AND Format = 'FLAC')) AND UserID = '$UserID'"); + list($PerfectFLACs) = $DB->next_record(); +} + +if (check_paranoia_here('seeding+')) { + $DB->query("SELECT COUNT(x.uid) FROM xbt_files_users AS x INNER JOIN torrents AS t ON t.ID=x.fid WHERE x.uid='$UserID' AND x.remaining=0"); + list($Seeding) = $DB->next_record(); +} + +if (check_paranoia_here('leeching+')) { + $DB->query("SELECT COUNT(x.uid) FROM xbt_files_users AS x INNER JOIN torrents AS t ON t.ID=x.fid WHERE x.uid='$UserID' AND x.remaining>0"); + list($Leeching) = $DB->next_record(); +} + +if(check_paranoia_here('invitedcount')) { + $DB->query("SELECT COUNT(UserID) FROM users_info WHERE Inviter='$UserID'"); + list($Invited) = $DB->next_record(); +} + +if (!$OwnProfile) { + $torrent_pass = ""; +} + +// Run through some paranoia stuff to decide what we can send out. +if (!check_paranoia_here('lastseen')) { + $LastAccess = ""; +} +if (!check_paranoia_here('uploaded')) { + $Uploaded = null; +} +if (!check_paranoia_here('downloaded')) { + $Downloaded = null; +} +if (isset($RequiredRatio) && !check_paranoia_here('requiredratio')) { + $RequiredRatio = null; +} +if($ParanoiaLevel == 0) { + $ParanoiaLevelText = 'Off'; +} elseif($ParanoiaLevel == 1) { + $ParanoiaLevelText = 'Very Low'; +} elseif($ParanoiaLevel <= 5) { + $ParanoiaLevelText = 'Low'; +} elseif($ParanoiaLevel <= 20) { + $ParanoiaLevelText = 'High'; +} else { + $ParanoiaLevelText = 'Very high'; +} + +header('Content-Type: text/plain; charset=utf-8'); + +print json_encode(array('status' => 'success', + 'response' => array( + 'username' => $Username, + 'avatar' => $Avatar, + 'isFriend' => $Friend, + 'profileText' => $Text->full_format($Info), + 'stats' => array( + 'joinedDate' => $JoinDate, + 'lastAccess' => $LastAccess, + 'uploaded' => $Uploaded == null ? null : (int) $Uploaded, + 'downloaded' => $Downloaded == null ? null: (int) $Downloaded, + 'ratio' => $Ratio, + 'requiredRatio' => $RequiredRatio == null ? null : (float) $RequiredRatio + ), + 'ranks' => array( + 'uploaded' => $UploadedRank, + 'downloaded' => $DownloadedRank, + 'uploads' => $UploadsRank, + 'requests' => $RequestRank, + 'bounty' => $BountyRank, + 'posts' => $PostRank, + 'artists' => $ArtistsRank, + 'overall' => $OverallRank == null ? 0 : $OverallRank + ), + 'personal' => array( + 'class' => $ClassLevels[$Class]['Name'], + 'paranoia' => $ParanoiaLevel, + 'paranoiaText' => $ParanoiaLevelText, + 'donor' => $Donor == 1, + 'warned' => ($Warned != '0000-00-00 00:00:00'), + 'enabled' => ($Enabled == '1' || $Enabled == '0' || !$Enabled), + 'passkey' => $torrent_pass + ), + 'community' => array( + 'posts' => (int) $ForumPosts, + 'torrentComments' => (int)$NumComments, + 'collagesStarted' => $NumCollages == null ? null : (int) $NumCollages, + 'collagesContrib' => $NumCollageContribs == null ? null : (int) $NumCollageContribs, + 'requestsFilled' => $RequestsFilled == null ? null : (int) $RequestsFilled, + 'requestsVoted' => $RequestsVoted == null ? null : (int) $RequestsVoted, + 'perfectFlacs' => $PerfectFLACs == null ? null : (int) $PerfectFlacs, + 'uploaded' => $Uploads == null ? null : (int) $Uploads, + 'groups' => $UniqueGroups == null ? null : (int) $UniqueGroups, + 'seeding' => $Seeding == null ? null : (int) $Seeding, + 'leeching' => $Leeching == null ? null : (int) $Leeching, + 'snatched' => $Snatched == null ? null : (int) $Snatched, + 'invited' => $Invited == null ? null : (int) $Invited + ) + ) + ) + ); // <- He's sad. +?> + diff --git a/sections/ajax/usersearch.php b/sections/ajax/usersearch.php new file mode 100644 index 00000000..46d5c5d0 --- /dev/null +++ b/sections/ajax/usersearch.php @@ -0,0 +1,60 @@ +>>>>>>>>>>>>>>>>>>>>>>>>>> User search <<<<<<<<<<<<<<<<<<<<<<<<<<<<* + **********************************************************************/ +authorize(true); + +if (!empty($_GET['search'])) { + + $_GET['username'] = $_GET['search']; +} + +define('USERS_PER_PAGE', 30); + +if(isset($_GET['username'])){ + $_GET['username'] = trim($_GET['username']); + + list($Page,$Limit) = page_limit(USERS_PER_PAGE); + $DB->query("SELECT SQL_CALC_FOUND_ROWS + ID, + Username, + Enabled, + PermissionID, + Donor, + Warned + FROM users_main AS um + JOIN users_info AS ui ON ui.UserID=um.ID + WHERE Username LIKE '%".db_string($_GET['username'])."%' + ORDER BY Username + LIMIT $Limit"); + $Results = $DB->to_array(); + $DB->query('SELECT FOUND_ROWS();'); + list($NumResults) = $DB->next_record(); + +} + +$JsonUsers = array(); +foreach($Results as $Result) { + list($UserID, $Username, $Enabled, $PermissionID, $Donor, $Warned) = $Result; + + $JsonUsers[] = array( + 'userId' => (int) $UserID, + 'username' => $Username, + 'donor' => $Donor == 1, + 'warned' => ($Warned!='0000-00-00 00:00:00'), + 'enabled' => ($Enabled == 2 ? false : true), + 'class' => make_class_string($PermissionID) + ); +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'currentPage' => (int) $Page, + 'pages' => ceil($NumResults/USERS_PER_PAGE), + 'results' => $JsonUsers + ) + ) + ); diff --git a/sections/api/access_state.php b/sections/api/access_state.php new file mode 100644 index 00000000..b086cda6 --- /dev/null +++ b/sections/api/access_state.php @@ -0,0 +1,12 @@ + diff --git a/sections/api/index.php b/sections/api/index.php new file mode 100644 index 00000000..b90f5530 --- /dev/null +++ b/sections/api/index.php @@ -0,0 +1,65 @@ +get_value('api_apps_'.$AppID); +if(!is_array($App)) { + if (!isset($DB)) { + require(SERVER_ROOT.'/classes/class_mysql.php'); + $DB = new DB_MYSQL; + } + $DB->query("SELECT Token, Name FROM api_applications WHERE ID='$AppID' LIMIT 1"); + $App = $DB->to_array(false,MYSQLI_ASSOC); + $Cache->cache_value('api_apps_'.$AppID, $App, 0); +} +$App = $App[0]; + +//Handle our request auths +if ($_GET['req'] === 'access_request') { + if (md5($App['Token']) !== $_GET['key']) { + error('invalid'); + } +} else { + $User = $Cache->get_value('api_users_'.$UserID); + if(!is_array($User)) { + if (!isset($DB)) { + require(SERVER_ROOT.'/classes/class_mysql.php'); + $DB = new DB_MYSQL; + } + $DB->query("SELECT AppID, Token, State, Time, Access FROM api_users WHERE UserID='$UserID' LIMIT 1"); //int, no db_string + $User = $DB->to_array('AppID',MYSQLI_ASSOC); + $Cache->cache_value('api_users_'.$UserID, $User, 0); + } + $User = $User[$AppID]; + + if (md5($User['Token'].$App['Token']) !== $_GET['key']) { + error('invalid'); + } +} + +die('API put on hold'); +require(SERVER_ROOT.'/sections/api/'.$_GET['req'].'.php'); +echo ''; +$Debug->profile(); diff --git a/sections/artist/add_alias.php b/sections/artist/add_alias.php new file mode 100644 index 00000000..1f79ecef --- /dev/null +++ b/sections/artist/add_alias.php @@ -0,0 +1,47 @@ +query("SELECT AliasID, ArtistID FROM artists_alias WHERE Name LIKE '".$AliasName."'"); +list($CloneAliasID, $CloneArtistID) = $DB->next_record(); +if($CloneAliasID) { + if($Redirect == 0) { + $DB->query("UPDATE artists_alias SET ArtistID='".$ArtistID."', Redirect=0 WHERE AliasID='".$CloneAliasID."'"); + } else { + error('An alias by that name already exists here. You can try renaming that artist to this one.'); + } +} + +$DB->query("INSERT INTO artists_alias(ArtistID, Name, Redirect, UserID) + VALUES + (".$ArtistID.", '".$AliasName."', ".$Redirect.", ".$LoggedUser['ID'].")"); +$AliasID = $DB->inserted_id(); + +$DB->query("SELECT Name FROM artists_group WHERE ArtistID=".$ArtistID); +list($ArtistName) = $DB->next_record(); + +write_log("The alias ".$AliasID." (".$AliasName.") was added to the artist ".$ArtistID." (".$ArtistName.") by user ".$LoggedUser['ID']." (".$LoggedUser['Username'].")"); + +header('Location: '.$_SERVER['HTTP_REFERER']); +?> diff --git a/sections/artist/add_similar.php b/sections/artist/add_similar.php new file mode 100644 index 00000000..a5007bb3 --- /dev/null +++ b/sections/artist/add_similar.php @@ -0,0 +1,51 @@ +query("SELECT ag.ArtistID FROM artists_group AS ag WHERE ag.Name LIKE '$Artist2Name'"); +list($Artist2ID) = $DB->next_record(); + +if(!empty($Artist2ID)) { // artist was found in the database + + // Let's see if there's already a similar artists field for these two + $DB->query("SELECT + s1.SimilarID + FROM artists_similar AS s1 + JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID + WHERE s1.ArtistID='$Artist1ID' AND s2.ArtistID='$Artist2ID'"); + list($SimilarID) = $DB->next_record(); + + if($SimilarID){ // The similar artists field already exists, just update the score + $DB->query("UPDATE artists_similar_scores SET Score=Score+200 WHERE SimilarID='$SimilarID'"); + } else { // No, it doesn't exist - create it + $DB->query("INSERT INTO artists_similar_scores (Score) VALUES ('200')"); + $SimilarID = $DB->inserted_id(); + $DB->query("INSERT INTO artists_similar (ArtistID, SimilarID) VALUES ('$Artist1ID', '$SimilarID')"); + $DB->query("INSERT INTO artists_similar (ArtistID, SimilarID) VALUES ('$Artist2ID', '$SimilarID')"); + } + + $DB->query("SELECT SimilarID FROM artists_similar_votes WHERE SimilarID='$SimilarID' AND UserID='$UserID' AND Way='up'"); + if($DB->record_count() == 0) { + $DB->query("INSERT INTO artists_similar_votes (SimilarID, UserID, way) VALUES ('$SimilarID', '$UserID', 'up')"); + } + + $Cache->delete('artist_'.$Artist1ID); // Delete artist cache + $Cache->delete('artist_'.$Artist2ID); // Delete artist cache + $Cache->delete('similar_positions_'.$Artist1ID); // Delete artist's similar map cache + $Cache->delete('similar_positions_'.$Artist2ID); // Delete artist's similar map cache +} + + +header('Location: '.$_SERVER['HTTP_REFERER']); +?> diff --git a/sections/artist/artist.php b/sections/artist/artist.php new file mode 100644 index 00000000..e9a23eca --- /dev/null +++ b/sections/artist/artist.php @@ -0,0 +1,815 @@ +get_value("artist_$ArtistID"."_revision_$RevisionID"); +} else { // viewing the live version + $Data = $Cache->get_value('artist_'.$ArtistID); + $RevisionID = false; +} +if($Data) { + $Data = unserialize($Data); + list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, $TorrentList, $Importances, $VanityHouseArtist)) = each($Data); + +} else { + if ($RevisionID) { + $sql = "SELECT + a.Name, + wiki.Image, + wiki.body, + a.VanityHouse + FROM wiki_artists AS wiki + LEFT JOIN artists_group AS a ON wiki.RevisionID=a.RevisionID + WHERE wiki.RevisionID='$RevisionID' "; + } else { + $sql = "SELECT + a.Name, + wiki.Image, + wiki.body, + a.VanityHouse + FROM artists_group AS a + LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID=a.RevisionID + WHERE a.ArtistID='$ArtistID' "; + } + $sql .= " GROUP BY a.ArtistID"; + $DB->query($sql); + + if($DB->record_count()==0) { error(404); } + + list($Name, $Image, $Body, $VanityHouseArtist) = $DB->next_record(MYSQLI_NUM, array(0)); +} + +$TokenTorrents = $Cache->get_value('users_tokens_'.$UserID); +if (empty($TokenTorrents)) { + $DB->query("SELECT TorrentID FROM users_freeleeches WHERE UserID=$UserID AND Expired=FALSE"); + $TokenTorrents = $DB->collect('TorrentID'); + $Cache->cache_value('users_tokens_'.$UserID, $TokenTorrents); +} + +//----------------- Build list and get stats + +ob_start(); + +// Requests +$Requests = $Cache->get_value('artists_requests_'.$ArtistID); +if(!is_array($Requests)) { + $DB->query("SELECT + r.ID, + r.CategoryID, + r.Title, + r.Year, + r.TimeAdded, + COUNT(rv.UserID) AS Votes, + SUM(rv.Bounty) AS Bounty + FROM requests AS r + LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID + LEFT JOIN requests_artists AS ra ON r.ID=ra.RequestID + WHERE ra.ArtistID = ".$ArtistID." + AND r.TorrentID = 0 + GROUP BY r.ID + ORDER BY Votes DESC"); + + if($DB->record_count() > 0) { + $Requests = $DB->to_array(); + } else { + $Requests = array(); + } + $Cache->cache_value('artists_requests_'.$ArtistID, $Requests); +} +$NumRequests = count($Requests); + +$LastReleaseType = 0; +if(empty($Importances) || empty($TorrentList)) { + $DB->query("SELECT + DISTINCTROW ta.GroupID, ta.Importance, tg.VanityHouse + FROM torrents_artists AS ta + JOIN torrents_group AS tg ON tg.ID=ta.GroupID + WHERE ta.ArtistID='$ArtistID' + ORDER BY IF(ta.Importance IN ('2', '3', '4', '7'),1000 + ta.Importance, tg.ReleaseType) ASC, + tg.Year DESC, tg.Name DESC"); + + $GroupIDs = $DB->collect('GroupID'); + $Importances = $DB->to_array(false, MYSQLI_BOTH, false); + + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs, true,true); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} +$NumGroups = count($TorrentList); + +if(!empty($TorrentList)) { +?> +
    +$Group) { + switch ($Importances[$ID]['Importance']) { + case '2': + $Importances[$ID]['ReleaseType'] = 1024; + //$TorrentList[$GroupID]['ReleaseType'] = 1024; + $GuestAlbums = true; + break; + + case '3': + $Importances[$ID]['ReleaseType'] = 1023; + //$TorrentList[$GroupID]['ReleaseType'] = 1023; + $RemixerAlbums = true; + break; + + case '4': + $Importances[$ID]['ReleaseType'] = 1022; + //$TorrentList[$GroupID]['ReleaseType'] = 1022; + $ComposerAlbums = true; + break; + + case '7': + $Importances[$ID]['ReleaseType'] = 1021; + //$TorrentList[$GroupID]['ReleaseType'] = 1021; + $ProducerAlbums = true; + break; + + default: + $Importances[$ID]['ReleaseType'] = $TorrentList[$Group['GroupID']]['ReleaseType']; + } + + if(!in_array($Importances[$ID]['ReleaseType'], $UsedReleases)) { + $UsedReleases[] = $Importances[$ID]['ReleaseType']; + } +} + +if(!empty($GuestAlbums)) { + $ReleaseTypes[1024] = "Guest Appearance"; +} +if(!empty($RemixerAlbums)) { + $ReleaseTypes[1023] = "Remixed By"; +} +if(!empty($ComposerAlbums)) { + $ReleaseTypes[1022] = "Composition"; +} +if(!empty($ProducerAlbums)) { + $ReleaseTypes[1021] = "Produced By"; +} + + +reset($TorrentList); +if(!empty($UsedReleases)) { ?> +
    + + ">[] + 0) { +?> + [Requests] + +
    + $Group) { + $TagList = explode(' ',str_replace('_','.',$Group['TagList'])); + + $TorrentTags = array(); + + // $Tags array is for the sidebar on the right. Skip compilations and soundtracks. + if (!in_array($ReleaseType, array(7, 3))) { + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + } + } + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags = '
    '.$TorrentTags.'
    '; + + foreach ($Group['Torrents'] as $TorrentID => $Torrent) { + $NumTorrents++; + + $Torrent['Seeders'] = (int)$Torrent['Seeders']; + $Torrent['Leechers'] = (int)$Torrent['Leechers']; + $Torrent['Snatched'] = (int)$Torrent['Snatched']; + + $NumSeeders+=$Torrent['Seeders']; + $NumLeechers+=$Torrent['Leechers']; + $NumSnatches+=$Torrent['Snatched']; + } +} + + + +$OpenTable = false; +$ShowGroups = !isset($LoggedUser['TorrentGrouping']) || $LoggedUser['TorrentGrouping'] == 0; +$HideTorrents = ($ShowGroups ? '' : ' hidden'); +$OldGroupID = 0; +$ReleaseType = 0; + +foreach ($Importances as $Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists, $ExtendedArtists) = array_values($TorrentList[$Group['GroupID']]); + $ReleaseType = $Group['ReleaseType']; + $GroupVanityHouse = $Group['VanityHouse']; + + if ($GroupID == $OldGroupID && $ReleaseType == $OldReleaseType) { + continue; + } else { + $OldGroupID = $GroupID; + $OldReleaseType = $ReleaseType; + } + + if (!empty($LoggedUser['DiscogView']) || (isset($LoggedUser['HideTypes']) && in_array($ReleaseType, $LoggedUser['HideTypes']))) { + $HideDiscog = ' hidden'; + } else { + $HideDiscog = ''; + } + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + + // $Tags array is for the sidebar on the right. Skip compilations and soundtracks. + foreach($TagList as $Tag) { + $TorrentTags[] = ''.$Tag.''; + } + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags = '
    '.$TorrentTags.'
    '; + + if($ReleaseType!=$LastReleaseType) { + switch($ReleaseTypes[$ReleaseType]) { + case "Remix" : + $DisplayName = "Remixes"; + break; + case "Anthology" : + $DisplayName = "Anthologies"; + break; + case "DJ Mix" : + $DisplayName = "DJ Mixes"; + break; + default : + $DisplayName = $ReleaseTypes[$ReleaseType]."s"; + break; + } + + $ReleaseTypeLabel = strtolower(str_replace(' ','_',$ReleaseTypes[$ReleaseType])); + if($OpenTable) { ?> +
    + + diff --git a/donate.php b/donate.php new file mode 100644 index 00000000..3e83e9a2 --- /dev/null +++ b/donate.php @@ -0,0 +1 @@ +EJ% zp!UL?&!65>qj4h3GIP0DzG8nmOU~aMGaqJ3yFV$N-!s?i$$qoRd|9bf*q)2q`M1+-c", + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $With=array( + ''','"','<','>', + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $Str=str_replace($Replace,$With,$Str); + } + return $Str; +} + +function make_utf8($Str) { + if ($Str!="") { + if (is_utf8($Str)) { $Encoding="UTF-8"; } + if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); } + if (empty($Encoding)) { $Encoding="ISO-8859-1"; } + if ($Encoding=="UTF-8") { return $Str; } + else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); } + } +} + +function is_utf8($Str) { + return preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] // ASCII + | [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16 + )*$%xs', $Str + ); +} + +function display_array($Array, $Escape = array()) { + foreach ($Array as $Key => $Val) { + if((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) { + $Array[$Key] = display_str($Val); + } + } + return $Array; +} + +header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0'); +header('Pragma:'); +header('Expires: '.date('D, d M Y H:i:s', time()+(2*60*60)).' GMT'); +header('Last-Modified: '.date('D, d M Y H:i:s').' GMT'); + +$Feed->UseSSL = (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443); +require(SERVER_ROOT.'/sections/feeds/index.php'); diff --git a/flush.php b/flush.php new file mode 100644 index 00000000..17b7d89c --- /dev/null +++ b/flush.php @@ -0,0 +1,18 @@ +decrypt($_COOKIE['session']); } +if(isset($LoginCookie)) { + list($SessionID, $UserID)=explode("|~|",$Enc->decrypt($LoginCookie)); + $UserID = (int)$UserID; + $UserInfo = $Cache->get_value('user_info_'.$UserID); + $Permissions = $Cache->get_value('perm_'.$UserInfo['PermissionID']); +} + +function check_perms($PermissionName) { + global $Permissions; + return (isset($Permissions['Permissions'][$PermissionName])) ? true : false; +} + +function error($Type) { + header('Content-type: image/gif'); + die(file_get_contents(SERVER_ROOT.'/sections/image/'.$Type.'.gif')); +} + +function invisible($Image) { + $Count = imagecolorstotal($Image); + if ($Count == 0) { return false; } + $TotalAlpha = 0; + for ($i=0; $i<$Count; ++$i) { + $Color = imagecolorsforindex($Image,$i); + $TotalAlpha += $Color['alpha']; + } + return (($TotalAlpha/$Count) == 127) ? true : false; + +} + +function is_number($Str) { + $Return = true; + if ($Str < 0) { $Return = false; } + // We're converting input to a int, then string and comparing to original + $Return = ($Str == strval(intval($Str)) ? true : false); + return $Return; +} + +function verysmall($Image) { + return ((imagesx($Image) * imagesy($Image)) < 25) ? true : false; +} + +function image_type($Data) { + if(!strncmp($Data,'GIF',3)) { + return 'gif'; + } + if(!strncmp($Data,pack('H*','89504E47'),4)) { + return 'png'; + } + if(!strncmp($Data,pack('H*','FFD8'),2)) { + return 'jpeg'; + } + if(!strncmp($Data,'BM',2)) { + return 'bmp'; + } + if(!strncmp($Data,'II',2) || !strncmp($Data,'MM',2)) { + return 'tiff'; + } +} + +function image_height($Type, $Data) { + $Length = strlen($Data); + global $URL, $_GET; + switch($Type) { + case 'jpeg': + // See http://www.obrador.com/essentialjpeg/headerinfo.htm + $i = 4; + $Data = (substr($Data, $i)); + $Block = unpack('nLength', $Data); + $Data = substr($Data, $Block['Length']); + $i+=$Block['Length']; + $Str []= "Started 4, + ".$Block['Length']; + while($Data!='') { // iterate through the blocks until we find the start of frame marker (FFC0) + $Block = unpack('CBlock/CType/nLength', $Data); // Get info about the block + if($Block['Block'] != '255') { break; } // We should be at the start of a new block + if($Block['Type'] != '192') { // C0 + $Data = substr($Data, $Block['Length']+2); // Next block + $Str []= "Started ".$i.", + ".($Block['Length']+2); + $i+=($Block['Length']+2); + } else { // We're at the FFC0 block + $Data = substr($Data, 5); // Skip FF C0 Length(2) precision(1) + $i+=5; + $Height = unpack('nHeight', $Data); + return $Height['Height']; + } + } + break; + case 'gif': + $Data = substr($Data, 8); + $Height = unpack('vHeight', $Data); + return $Height['Height']; + case 'png': + $Data = substr($Data, 20); + $Height = unpack('NHeight', $Data); + return $Height['Height']; + default: + return 0; + } +} + + +function send_pm($ToID,$FromID,$Subject,$Body,$ConvID='') { + global $DB, $Cache; + if($ToID==0) { + // Don't allow users to send messages to the system + return; + } + if($ConvID=='') { + $DB->query("INSERT INTO pm_conversations(Subject) VALUES ('".$Subject."')"); + $ConvID = $DB->inserted_id(); + $DB->query("INSERT INTO pm_conversations_users + (UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES + ('$ToID', '$ConvID', '1','0','".sqltime()."', '".sqltime()."', '1')"); + if ($FromID != 0) { + $DB->query("INSERT INTO pm_conversations_users + (UserID, ConvID, InInbox, InSentbox, SentDate, ReceivedDate, UnRead) VALUES + ('$FromID', '$ConvID', '0','1','".sqltime()."', '".sqltime()."', '0')"); + } + } else { + $DB->query("UPDATE pm_conversations_users SET + InInbox='1', + UnRead='1', + ReceivedDate='".sqltime()."' + WHERE UserID='$ToID' + AND ConvID='$ConvID'"); + + $DB->query("UPDATE pm_conversations_users SET + InSentbox='1', + SentDate='".sqltime()."' + WHERE UserID='$FromID' + AND ConvID='$ConvID'"); + } + $DB->query("INSERT INTO pm_messages + (SenderID, ConvID, SentDate, Body) VALUES + ('$FromID', '$ConvID', '".sqltime()."', '".$Body."')"); + + // Clear the caches of the inbox and sentbox + //$DB->query("SELECT UnRead from pm_conversations_users WHERE ConvID='$ConvID' AND UserID='$ToID'"); + $DB->query("SELECT COUNT(ConvID) FROM pm_conversations_users WHERE UnRead = '1' and UserID='$ToID' AND InInbox = '1'"); + list($UnRead) = $DB->next_record(MYSQLI_BOTH, FALSE); + $Cache->cache_value('inbox_new_'.$ToID, $UnRead); + + //if ($UnRead == 0) { + // $Cache->increment('inbox_new_'.$ToID); + //} + return $ConvID; +} + +function send_irc($Raw) { + $IRCSocket = fsockopen(SOCKET_LISTEN_ADDRESS, SOCKET_LISTEN_PORT); + fwrite($IRCSocket, $Raw); + fclose($IRCSocket); +} + +function display_str($Str) { + if ($Str === NULL || $Str === FALSE || is_array($Str)) { + return ''; + } + if ($Str!='' && !is_number($Str)) { + $Str=make_utf8($Str); + $Str=mb_convert_encoding($Str,"HTML-ENTITIES","UTF-8"); + $Str=preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,5};)/m","&",$Str); + + $Replace = array( + "'",'"',"<",">", + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $With=array( + ''','"','<','>', + '€','‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹','Œ','Ž','‘','’','“','”','•','–','—','˜','™','š','›','œ','ž','Ÿ' + ); + + $Str=str_replace($Replace,$With,$Str); + } + return $Str; +} + +function make_utf8($Str) { + if ($Str!="") { + if (is_utf8($Str)) { $Encoding="UTF-8"; } + if (empty($Encoding)) { $Encoding=mb_detect_encoding($Str,'UTF-8, ISO-8859-1'); } + if (empty($Encoding)) { $Encoding="ISO-8859-1"; } + if ($Encoding=="UTF-8") { return $Str; } + else { return @mb_convert_encoding($Str,"UTF-8",$Encoding); } + } +} + +function is_utf8($Str) { + return preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] // ASCII + | [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16 + )*$%xs', $Str + ); +} + +require(SERVER_ROOT.'/sections/image/index.php'); +?> diff --git a/inbox.php b/inbox.php new file mode 100644 index 00000000..3e83e9a2 --- /dev/null +++ b/inbox.php @@ -0,0 +1 @@ + diff --git a/login.php b/login.php new file mode 100644 index 00000000..3e83e9a2 --- /dev/null +++ b/login.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/opensearch.php b/opensearch.php new file mode 100644 index 00000000..47cc0aa4 --- /dev/null +++ b/opensearch.php @@ -0,0 +1,73 @@ +'; ?> + + + + Search for + + http:///favicon.ico + + + + http:///torrents.php?action=advanced + + + http:///torrents.php + + + http:///requests.php + + + http:///forums.php?action=search + + + http:///user.php?action=search + + + http:///wiki.php?action=search + + + http:///log.php + + + en-us + UTF-8 + UTF-8 + diff --git a/peerupdate.php b/peerupdate.php new file mode 100644 index 00000000..901fbd7e --- /dev/null +++ b/peerupdate.php @@ -0,0 +1,6 @@ + diff --git a/robots.txt b/robots.txt new file mode 100644 index 00000000..44227d7b --- /dev/null +++ b/robots.txt @@ -0,0 +1,10 @@ +User-agent: * +Allow: /index.php +Allow: /login.php +Allow: /register.php +# +Allow: /what-network/ +Allow: /gazelle/ +Sitemap: http://what.cd/sitemap.xml +# +Disallow: / diff --git a/rules.php b/rules.php new file mode 100644 index 00000000..73977506 --- /dev/null +++ b/rules.php @@ -0,0 +1 @@ +get_value('news')) { + $DB->query("SELECT + ID, + Title, + Body, + Time + FROM news + ORDER BY Time DESC + LIMIT 5"); + $News = $DB->to_array(false,MYSQLI_NUM,false); + $Cache->cache_value('news',$News,3600*24*30); + $Cache->cache_value('news_latest_id', $News[0][0], 0); +} + +if ($LoggedUser['LastReadNews'] != $News[0][0]) { + $Cache->begin_transaction('user_info_heavy_'.$UserID); + $Cache->update_row(false, array('LastReadNews' => $News[0][0])); + $Cache->commit_transaction(0); + $DB->query("UPDATE users_info SET LastReadNews = '".$News[0][0]."' WHERE UserID = ".$UserID); + $LoggedUser['LastReadNews'] = $News[0][0]; +} + +if(($Blog = $Cache->get_value('blog')) === false) { + $DB->query("SELECT + b.ID, + um.Username, + b.Title, + b.Body, + b.Time, + b.ThreadID + FROM blog AS b LEFT JOIN users_main AS um ON b.UserID=um.ID + ORDER BY Time DESC + LIMIT 20"); + $Blog = $DB->to_array(); + $Cache->cache_value('blog',$Blog,1209600); +} + +$JsonBlog = array(); +for ($i = 0; $i < $Limit; $i++) { + list($BlogID, $Author, $Title, $Body, $BlogTime, $ThreadID) = $Blog[$i]; + $JsonBlog[] = array( + 'blogId' => (int) $BlogID, + 'author' => $Author, + 'title' => $Title, + 'body' => $Text->full_format($Body), + 'blogTime' => $BlogTime, + 'threadId' => (int) $ThreadID + ); +} + +$JsonAnnouncements = array(); +$Count = 0; +foreach ($News as $NewsItem) { + list($NewsID,$Title,$Body,$NewsTime) = $NewsItem; + if (strtotime($NewsTime) > time()) { + continue; + } + + $JsonAnnouncements[] = array( + 'newsId' => (int) $NewsID, + 'title' => $Title, + 'body' => $Text->full_format($Body), + 'newsTime' => $NewsTime + ); + + if (++$Count > 4) { + break; + } +} + +print + json_encode( + array( + 'status' => 'success', + 'response' => array( + 'announcements' => $JsonAnnouncements, + 'blogPosts' => $JsonBlog + ) + ) + ); + +?> \ No newline at end of file diff --git a/sections/ajax/artist.php b/sections/ajax/artist.php new file mode 100644 index 00000000..8a56c1fd --- /dev/null +++ b/sections/ajax/artist.php @@ -0,0 +1,388 @@ + 'failure')); +} + +if (empty($ArtistID)) { + if (!empty($_GET['artistname'])) { + $Name = db_string(trim($_GET['artistname'])); + $DB->query("SELECT ArtistID FROM artists_alias WHERE Name LIKE '$Name'"); + if (!(list($ArtistID) = $DB->next_record(MYSQLI_NUM, false))) { + //if (list($ID) = $DB->next_record(MYSQLI_NUM, false)) { + print json_encode(array('status' => 'failure')); + die(); + } + // If we get here, we got the ID! + } +} + +if(!empty($_GET['revisionid'])) { // if they're viewing an old revision + $RevisionID=$_GET['revisionid']; + if(!is_number($RevisionID)){ error(0); } + $Data = $Cache->get_value("artist_$ArtistID"."_revision_$RevisionID"); +} else { // viewing the live version + $Data = $Cache->get_value('artist_'.$ArtistID); + $RevisionID = false; +} +if($Data) { + $Data = unserialize($Data); + list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, $TorrentList, $Importances)) = each($Data); + +} else { + if ($RevisionID) { + $sql = "SELECT + a.Name, + wiki.Image, + wiki.body, + a.VanityHouse + FROM wiki_artists AS wiki + LEFT JOIN artists_group AS a ON wiki.RevisionID=a.RevisionID + WHERE wiki.RevisionID='$RevisionID' "; + } else { + $sql = "SELECT + a.Name, + wiki.Image, + wiki.body, + a.VanityHouse + FROM artists_group AS a + LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID=a.RevisionID + WHERE a.ArtistID='$ArtistID' "; + } + $sql .= " GROUP BY a.ArtistID"; + $DB->query($sql); + + if($DB->record_count()==0) { + print json_encode(array('status' => 'failure')); + } + + list($Name, $Image, $Body, $VanityHouseArtist) = $DB->next_record(MYSQLI_NUM, array(0)); +} + +ob_start(); + +// Requests +$Requests = $Cache->get_value('artists_requests_'.$ArtistID); +if(!is_array($Requests)) { + $DB->query("SELECT + r.ID, + r.CategoryID, + r.Title, + r.Year, + r.TimeAdded, + COUNT(rv.UserID) AS Votes, + SUM(rv.Bounty) AS Bounty + FROM requests AS r + LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID + LEFT JOIN requests_artists AS ra ON r.ID=ra.RequestID + WHERE ra.ArtistID = ".$ArtistID." + AND r.TorrentID = 0 + GROUP BY r.ID + ORDER BY Votes DESC"); + + if($DB->record_count() > 0) { + $Requests = $DB->to_array(); + } else { + $Requests = array(); + } + $Cache->cache_value('artists_requests_'.$ArtistID, $Requests); +} +$NumRequests = count($Requests); + +$LastReleaseType = 0; +if(empty($Importances) || empty($TorrentList)) { + $DB->query("SELECT + DISTINCT ta.GroupID, ta.Importance, tg.VanityHouse + FROM torrents_artists AS ta + JOIN torrents_group AS tg ON tg.ID=ta.GroupID + WHERE ta.ArtistID='$ArtistID' + ORDER BY IF(ta.Importance IN ('2', '3', '4', '7'),ta.Importance, 1), + tg.ReleaseType ASC, tg.Year DESC, tg.Name DESC"); + + $GroupIDs = $DB->collect('GroupID'); + $Importances = $DB->to_array('GroupID', MYSQLI_BOTH, false); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs, true,true); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} +$NumGroups = count($TorrentList); + +//Get list of used release types +$UsedReleases = array(); +foreach($TorrentList as $GroupID=>$Group) { + if($Importances[$GroupID]['Importance'] == '2') { + $TorrentList[$GroupID]['ReleaseType'] = 1024; + $GuestAlbums = true; + } + if($Importances[$GroupID]['Importance'] == '3') { + $TorrentList[$GroupID]['ReleaseType'] = 1023; + $RemixerAlbums = true; + } + if($Importances[$GroupID]['Importance'] == '4') { + $TorrentList[$GroupID]['ReleaseType'] = 1022; + $ComposerAlbums = true; + } + if($Importances[$GroupID]['Importance'] == '7') { + $TorrentList[$GroupID]['ReleaseType'] = 1021; + $ProducerAlbums = true; + } + if(!in_array($TorrentList[$GroupID]['ReleaseType'], $UsedReleases)) { + $UsedReleases[] = $TorrentList[$GroupID]['ReleaseType']; + } +} + +if(!empty($GuestAlbums)) { + $ReleaseTypes[1024] = "Guest Appearance"; +} +if(!empty($RemixerAlbums)) { + $ReleaseTypes[1023] = "Remixed By"; +} +if(!empty($ComposerAlbums)) { + $ReleaseTypes[1022] = "Composition"; +} +if(!empty($ProducerAlbums)) { + $ReleaseTypes[1021] = "Produced By"; +} + +reset($TorrentList); + +$JsonTorrents = array(); +foreach ($TorrentList as $GroupID=>$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists, $ExtendedArtists) = array_values($Group); + $GroupVanityHouse = $Importances[$GroupID]['VanityHouse']; + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + // $Tags array is for the sidebar on the right + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + } + + + + $DisplayName =''.$GroupName.''; + if(check_perms('users_mod')) { + $DisplayName .= ' [Fix]'; + } + + switch($ReleaseType){ + case 1023: // Remixes, DJ Mixes, Guest artists, and Producers need the artist name + case 1024: + case 1021: + case 8: + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName = display_artists($ExtendedArtists).$DisplayName; + } elseif(count($GroupArtists)>0) { + $DisplayName = display_artists(array(1 => $Artists), true, true).$DisplayName; + } + break; + case 1022: // Show performers on composer pages + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5])) { + unset($ExtendedArtists[4]); + unset($ExtendedArtists[3]); + unset($ExtendedArtists[6]); + $DisplayName = display_artists($ExtendedArtists).$DisplayName; + } elseif(count($GroupArtists)>0) { + $DisplayName = display_artists(array(1 => $Artists), true, true).$DisplayName; + } + break; + default: // Show composers otherwise + if (!empty($ExtendedArtists[4])) { + $DisplayName = display_artists(array(4 => $ExtendedArtists[4]), true, true).$DisplayName; + } + } + + if($GroupYear>0) { $DisplayName = $GroupYear. ' - '.$DisplayName; } + + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + +?> +
    +
    + +
    +
    + + +
    + + + + + + + + + + +'.$GroupName.''; + if(check_perms('users_mod')) { + $DisplayName .= ' [Fix]'; + } + + + switch($ReleaseType){ + case 1023: // Remixes, DJ Mixes, Guest artists, and Producers need the artist name + case 1024: + case 1021: + case 8: + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName = display_artists($ExtendedArtists).$DisplayName; + } elseif(count($GroupArtists)>0) { + $DisplayName = display_artists(array(1 => $Artists), true, true).$DisplayName; + } + break; + case 1022: // Show performers on composer pages + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5])) { + unset($ExtendedArtists[4]); + unset($ExtendedArtists[3]); + unset($ExtendedArtists[6]); + $DisplayName = display_artists($ExtendedArtists).$DisplayName; + } elseif(count($GroupArtists)>0) { + $DisplayName = display_artists(array(1 => $Artists), true, true).$DisplayName; + } + break; + default: // Show composers otherwise + if (!empty($ExtendedArtists[4])) { + $DisplayName = display_artists(array(4 => $ExtendedArtists[4]), true, true).$DisplayName; + } + } + + if($GroupYear>0) { $DisplayName = $GroupYear. ' - '.$DisplayName; } + + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + +?> + + + + + $Torrent) { + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if (in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent'])) { + $Torrent['PersonalFL'] = 1; + } + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) { + + $EditionID++; + + if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) { + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + +?> + + + + + + + + + + + + + > + + + +
      (View)SizeSnatchesSeedersLeechers
    +
    + +
    +
    + + +
    + + [ + 0) && ($Torrent['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1')) { ?> + | FL + ] + +   »  +
    +
    + +
    +

    (Revision #) [Vanity House]

    + + +
    + 0) { + +?> + + + + + + + +".$Title." [".$Year."]"; + } else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + $FullName = "".$Title." [".$Year."]"; + } else { + $FullName ="".$Title.""; + } + + $Row = ($Row == 'a') ? 'b' : 'a'; + + $Tags = get_request_tags($RequestID); +?> + + + + + + + +
    +   + Request Name + + Vote + + Bounty + + Added +
    + +
    + $TagName) { + $TagList[] = "".display_str($TagName).""; + } + $TagList = implode(', ', $TagList); +?> + +
    +
    + + + +    (+) + + + + + +
    +0) { + if($SimilarData = $Cache->get_value('similar_positions_'.$ArtistID)) { + $Similar = new ARTISTS_SIMILAR($ArtistID, $Name); + $Similar->load_data($SimilarData); + if(!(current($Similar->Artists)->NameLength)) { + unset($Similar); + } + } + if(empty($Similar) || empty($Similar->Artists)) { + include(SERVER_ROOT.'/classes/class_image.php'); + $Img = new IMAGE; + $Img->create(WIDTH, HEIGHT); + $Img->color(255,255,255, 127); + + $Similar = new ARTISTS_SIMILAR($ArtistID, $Name); + $Similar->set_up(); + $Similar->set_positions(); + $Similar->background_image(); + + $SimilarData = $Similar->dump_data(); + + $Cache->cache_value('similar_positions_'.$ArtistID, $SimilarData, 3600*24); + } +?> + +
    +
    Similar artist map
    +
    +write_artists(); +?> +
    +
    +0 ?> +
    +
    Artist info
    +
    full_format($Body)?>
    +
    +
    +
    +cache_value($Key, $Data, 3600); +?> diff --git a/sections/artist/artist_rearrange.php b/sections/artist/artist_rearrange.php new file mode 100644 index 00000000..122a5320 --- /dev/null +++ b/sections/artist/artist_rearrange.php @@ -0,0 +1,690 @@ +get_value("artist_$ArtistID"."_revision_$RevisionID"); +} else { // viewing the live version + $Data = $Cache->get_value('artist_'.$ArtistID); + $RevisionID = false; +} +if($Data) { + $Data = unserialize($Data); + list($K, list($Name, $Image, $Body, $NumSimilar, $SimilarArray, $TorrentList, $GroupMeta)) = each($Data); + +} else { + $sql = "SELECT + a.Name, + wiki.Image, + wiki.body, + a.VanityHouse + FROM artists_group AS a + LEFT JOIN wiki_artists AS wiki ON wiki.RevisionID=a.RevisionID + WHERE "; + if($RevisionID){ + $sql.=" wiki.RevisionID='$RevisionID' "; + } else { + $sql.=" a.ArtistID='$ArtistID' "; + } + $sql .= " GROUP BY a.ArtistID"; + $DB->query($sql, MYSQLI_NUM, true); + + if($DB->record_count()==0) { error(404); } + + list($Name, $Image, $Body, $VanityHouseArtist) = $DB->next_record(); +} + +//----------------- Build list and get stats + +ob_start(); + + +// Requests +$Requests = $Cache->get_value('artists_requests_'.$ArtistID); +if(!is_array($Requests)) { + $DB->query("SELECT + r.ID, + r.CategoryID, + r.Title, + r.Year, + r.TimeAdded, + COUNT(rv.UserID) AS Votes, + SUM(rv.Bounty) AS Bounty + FROM requests AS r + LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID + LEFT JOIN requests_artists AS ra ON r.ID=ra.RequestID + WHERE ra.ArtistID = ".$ArtistID." + AND r.TorrentID = 0 + GROUP BY r.ID + ORDER BY Votes DESC"); + + if($DB->record_count() > 0) { + $Requests = $DB->to_array(); + } else { + $Requests = array(); + } + $Cache->cache_value('artists_requests_'.$ArtistID, $Requests); +} +$NumRequests = count($Requests); + +$LastReleaseType = 0; +if(empty($GroupMeta) || empty($TorrentList)) { + $DB->query("SELECT + DISTINCT ta.GroupID, ta.Importance, tg.VanityHouse + FROM torrents_artists AS ta + JOIN torrents_group AS tg ON tg.ID=ta.GroupID + WHERE ta.ArtistID='$ArtistID' + ORDER BY ta.Importance, tg.ReleaseType ASC, tg.Year DESC"); + + $GroupIDs = $DB->collect('GroupID'); + $GroupMeta = $DB->to_array('GroupID', MYSQLI_BOTH, false); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs, true, true); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} +$NumGroups = count($TorrentList); + +if(!empty($TorrentList)) { +?> +
    + $ReleaseType) { + if(!array_key_exists($ReleaseType, $ReleaseTypesOrder)) { + $ReleaseTypesOrder[$ReleaseType] = $HasShown ? 1 : 0; // If no releasetype is open by default assume (s)he wants them all closed + } + } +} else { + // Load defaults + $ReleaseTypesOrder = array_flip($ReleaseTypesDefaultOrder); +} + +foreach($ReleaseTypesOrder as $ReleaseType => $ReleaseTypeName) { + $TorrentListByReleaseType[$ReleaseType] = array(); +} + +//Names for releasetypes that are not uploadable but exist in the defaultordering +$ReleaseTypes[1023] = "Remixed By"; +$ReleaseTypes[1024] = "Guest Appearance"; + +foreach($TorrentList as $GroupID=>$Group) { + if($GroupMeta[$GroupID]['Importance'] == '2') { + $TorrentList[$GroupID]['ReleaseType'] = 1024; + } + if($GroupMeta[$GroupID]['Importance'] == '3') { + $TorrentList[$GroupID]['ReleaseType'] = 1023; + } + if(!in_array($TorrentList[$GroupID]['ReleaseType'], $UsedReleases)) { + $UsedReleases[] = $TorrentList[$GroupID]['ReleaseType']; + } + $TorrentListByReleaseType[$TorrentList[$GroupID]['ReleaseType']][$GroupID] = $Group; +} + +reset($TorrentList); +if(!empty($UsedReleases)) { ?> +
    + + $Torrents) { + if(!in_array($ReleaseID, $UsedReleases)) { + continue; + } + switch($ReleaseTypes[$ReleaseID]) { + case "Remix" : + $DisplayName = "Remixes"; + break; + case "Anthology" : + $DisplayName = "Anthologies"; + break; + default : + $DisplayName = $ReleaseTypes[$ReleaseID]."s"; + break; + } + +?> + " id="torrents__anchorlink">[] + 0) { +?> + [Requests] + + + +
    + +
    + $TorrentListForReleaseType) { + $NumTorrentsReleaseType = count($TorrentListForReleaseType); + if($OpenTable) { + ?> + " id="torrents_"> + + + + + + + + + + $Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $NewReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists) = array_values($Group); + $GroupVanityHouse = $GroupMeta[$GroupID]['VanityHouse']; + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + + // $Tags array is for the sidebar on the right + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + $TorrentTags[]=''.$Tag.''; + } + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags = '
    '.$TorrentTags.'
    '; + + if (($ReleaseType == 1023) || ($ReleaseType == 1024)) { + $ArtistPrefix = display_artists(array(1 => $GroupArtists)); + } else { + $ArtistPrefix = ''; + } + + $DisplayName = $ArtistPrefix . ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $GroupYear. ' - '.$DisplayName; } + + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + +?> + + + + + $Torrent) { + $NumTorrents++; + + $Torrent['Seeders'] = (int)$Torrent['Seeders']; + $Torrent['Leechers'] = (int)$Torrent['Leechers']; + $Torrent['Snatched'] = (int)$Torrent['Snatched']; + + $NumSeeders+=$Torrent['Seeders']; + $NumLeechers+=$Torrent['Leechers']; + $NumSnatches+=$Torrent['Snatched']; + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $Torrent['Media'] != $LastMedia) { + + $EditionID++; + + if($Torrent['RemasterTitle'] || $Torrent['RemasterYear'] || $Torrent['RemasterRecordLabel'] || $Torrent['RemasterCatalogueNumber']) { + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + +?> + + + + + + + + + + + + + + + + + +
    + + 0) { ?> + + +   +   + + 0) { ?> + ( id="releases__viewlink" onclick="setShow('',true);return false;">View id="releases__hidelink" onclick="setShow('',false);return false;">Hide) + + + SizeSnatchesSeedersLeechers
    +
    +
    + + +
    + + [DL] + +   »  +
    +
    + +
    + +
    +

    (Revision #) [Vanity House]

    + + [Edit ordering] + + + + + + + +
    + 0) { + +?> + + + + + + + +".$Title." [".$Year."]"; + } else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + $FullName = "".$Title." [".$Year."]"; + } else { + $FullName ="".$Title.""; + } + + $Row = ($Row == 'a') ? 'b' : 'a'; + + $Tags = get_request_tags($RequestID); +?> + + + + + + + +
    +   + Request Name + + Vote + + Bounty + + Added +
    + +
    + $TagName) { + $TagList[] = "".display_str($TagName).""; + } + $TagList = implode(', ', $TagList); +?> + +
    +
    + + + +    (+) + + + + + +
    +0) { + $SimilarData = $Cache->get_value('similar_positions_'.$ArtistID); + + if(!$Data) { + include(SERVER_ROOT.'/classes/class_image.php'); + $Img = new IMAGE; + $Img->create(WIDTH, HEIGHT); + $Img->color(255,255,255, 127); + + $Similar = new ARTISTS_SIMILAR($ArtistID, $Name); + $Similar->set_up(); + $Similar->set_positions(); + $Similar->background_image(); + + + $SimilarData = $Similar->dump_data(); + + $Cache->cache_value('similar_positions_'.$ArtistID, $SimilarData, 3600*24); + } else { + $Similar = new ARTISTS_SIMILAR($ArtistID); + $Similar->load_data($SimilarData); + } +?> + +
    +
    Similar artist map
    +
    +write_artists(); +?> +
    +
    +0 ?> +
    +
    Artist info
    +
    full_format($Body)?>
    +
    +
    +
    +cache_value($Key, $Data, 3600); +?> diff --git a/sections/artist/autocomplete.php b/sections/artist/autocomplete.php new file mode 100644 index 00000000..d199064c --- /dev/null +++ b/sections/artist/autocomplete.php @@ -0,0 +1,54 @@ +get('autocomplete_artist_'.$KeySize.'_'.$Letters); +if(!is_array($AutoSuggest)) { + if(!isset($DB) || !is_object($DB)) { + require(SERVER_ROOT.'/classes/class_mysql.php'); //Require the database wrapper + $DB=NEW DB_MYSQL; //Load the database wrapper + } + $Limit = (($KeySize === $MaxKeySize)?250:10); + $DB->query("SELECT + a.ArtistID, + a.Name, + SUM(t.Snatched) AS Snatches + FROM artists_group AS a + INNER JOIN torrents_artists AS ta ON ta.ArtistID=a.ArtistID + INNER JOIN torrents AS t ON t.GroupID=ta.GroupID + WHERE a.Name LIKE '".db_string($Letters)."%' + GROUP BY ta.ArtistID + ORDER BY Snatches DESC + LIMIT $Limit"); + $AutoSuggest = $DB->to_array(false,MYSQLI_NUM,false); + $Cache->cache_value('autocomplete_artist_'.$KeySize.'_'.$Letters,$AutoSuggest,1800+7200*($MaxKeySize-$KeySize)); // Can't cache things for too long in case names are edited +} + +$Matched = 0; +$Suggestions = array(); +$Snatches = array(); +$Links = array(); +foreach ($AutoSuggest as $Suggestion) { + list($ID,$Name, $Snatch) = $Suggestion; + if (stripos($Name,$FullName) === 0) { + $Suggestions[] = display_str($Name); + $Snatches[] = number_format($Snatch).' snatches'; + $Links[] = 'http'.($SSL?'s':'').'://'.$_SERVER['HTTP_HOST'].'/artist.php?id='.$ID; + if (++$Matched > 9) { + break; + } + } +} + +echo json_encode(array($FullName,$Suggestions,$Snatches,$Links)); diff --git a/sections/artist/delete.php b/sections/artist/delete.php new file mode 100644 index 00000000..13498517 --- /dev/null +++ b/sections/artist/delete.php @@ -0,0 +1,84 @@ +query('SELECT Name FROM artists_group WHERE ArtistID='.$ArtistID); +list($Name) = $DB->next_record(); + +$DB->query('SELECT tg.Name, + tg.ID + FROM torrents_group AS tg + LEFT JOIN torrents_artists AS ta ON ta.GroupID=tg.ID + WHERE ta.ArtistID='.$ArtistID); +$Count = $DB->record_count(); +if($DB->record_count() > 0) { +?> +
    + There are still torrents that have as an artist
    + Please remove the artist from these torrents manually before attempting to delete.
    +
    +
      +next_record(MYSQLI_NUM, true)) { +?> +
    • + +
    • + +
    +
    +
    +query('SELECT r.Title, + r.ID + FROM requests AS r + LEFT JOIN requests_artists AS ra ON ra.RequestID=r.ID + WHERE ra.ArtistID='.$ArtistID); +$Count += $DB->record_count(); +if($DB->record_count() > 0) { +?> +
    + There are still requests that have as an artist
    + Please remove the artist from these requests manually before attempting to delete.
    +
    +
      +next_record(MYSQLI_NUM, true)) { +?> +
    • + +
    • + +
    +
    +
    + +
    Artist deleted!
    + diff --git a/sections/artist/delete_alias.php b/sections/artist/delete_alias.php new file mode 100644 index 00000000..cbb6ea9d --- /dev/null +++ b/sections/artist/delete_alias.php @@ -0,0 +1,37 @@ +query("SELECT aa.AliasID + FROM artists_alias AS aa + JOIN artists_alias AS aa2 ON aa.ArtistID=aa2.ArtistID + WHERE aa.AliasID=".$AliasID); + +if($DB->record_count() == 1) { + //This is the last alias on the artist + error("That alias is the last alias for that artist, removing it would cause bad things to happen."); +} + +$DB->query("SELECT GroupID FROM torrents_artists WHERE AliasID='$AliasID'"); +if($DB->record_count() > 0) { + list($GroupID) = $DB->next_record(); + if($GroupID != 0) { + error("That alias still has the group ($GroupID) attached, fix that first."); + } +} + +$DB->query("SELECT aa.ArtistID, ag.Name, aa.Name FROM artists_alias AS aa JOIN artists_group AS ag ON aa.ArtistID=ag.ArtistID WHERE aa.AliasID=".$AliasID); +list($ArtistID, $ArtistName, $AliasName) = $DB->next_record(MYSQLI_NUM, false); + +$DB->query("DELETE FROM artists_alias WHERE AliasID='$AliasID'"); +$DB->query("UPDATE artists_alias SET Redirect='0' WHERE Redirect='$AliasID'"); + +write_log("The alias ".$AliasID." (".db_string($AliasName).") was removed from the artist ".$ArtistID." (".db_string($ArtistName).") by user ".$LoggedUser['ID']." (".db_string($LoggedUser['Username']).")"); + +header('Location: '.$_SERVER['HTTP_REFERER']); diff --git a/sections/artist/delete_similar.php b/sections/artist/delete_similar.php new file mode 100644 index 00000000..0e45ab9a --- /dev/null +++ b/sections/artist/delete_similar.php @@ -0,0 +1,23 @@ +query("SELECT ArtistID FROM artists_similar WHERE SimilarID='$SimilarID'"); +$ArtistIDs = $DB->to_array(); +$DB->query("DELETE FROM artists_similar WHERE SimilarID='$SimilarID'"); +$DB->query("DELETE FROM artists_similar_scores WHERE SimilarID='$SimilarID'"); +$DB->query("DELETE FROM artists_similar_votes WHERE SimilarID='$SimilarID'"); + +foreach ($ArtistIDs as $ArtistID) { + list($ArtistID) = $ArtistID; + $Cache->delete_value('artist_'.$ArtistID); // Delete artist cache + $Cache->delete_value('similar_positions_'.$ArtistID); +} +header('Location: '.$_SERVER['HTTP_REFERER']); +?> diff --git a/sections/artist/download.php b/sections/artist/download.php new file mode 100644 index 00000000..cffb2412 --- /dev/null +++ b/sections/artist/download.php @@ -0,0 +1,206 @@ +to_array() works. What we've done, is +backwards ordering. The results returned by the +query have the best one for each GroupID last, +and while to_array traverses the results, it +overwrites the keys and leaves us with only the +desired result. This does mean however, that +the SQL has to be done in a somewhat backwards +fashion. + +Thats all you get for a disclaimer, just +remember, this page isn't for the faint of +heart. -A9 + +SQL template: +SELECT + CASE + WHEN t.Format='Ogg Vorbis' THEN 0 + WHEN t.Format='MP3' AND t.Encoding='V0 (VBR)' THEN 1 + WHEN t.Format='MP3' AND t.Encoding='V2 (VBR)' THEN 2 + ELSE 100 + END AS Rank, + t.GroupID, + t.Media, + t.Format, + t.Encoding, + IF(t.Year=0,tg.Year,t.Year), + tg.Name, + a.Name, + t.Size +FROM torrents AS t +INNER JOIN torrents_group AS tg ON tg.ID=t.GroupID AND tg.CategoryID='1' +INNER JOIN artists_group AS a ON a.ArtistID=tg.ArtistID AND a.ArtistID='59721' +LEFT JOIN torrents_files AS f ON t.ID=f.TorrentID +ORDER BY t.GroupID ASC, Rank DESC, t.Seeders ASC +*/ + +if( + !isset($_REQUEST['artistid']) || + !isset($_REQUEST['preference']) || + !is_number($_REQUEST['preference']) || + !is_number($_REQUEST['artistid']) || + $_REQUEST['preference'] > 2 || + count($_REQUEST['list']) == 0 +) { error(0); } + +if(!check_perms('zip_downloader')){ error(403); } + +$Preferences = array('RemasterTitle DESC','Seeders ASC','Size ASC'); + +$ArtistID = $_REQUEST['artistid']; +$Preference = $Preferences[$_REQUEST['preference']]; + +$DB->query("SELECT Name FROM artists_group WHERE ArtistID='$ArtistID'"); +list($ArtistName) = $DB->next_record(MYSQLI_NUM,false); + +$DB->query("SELECT GroupID, Importance FROM torrents_artists WHERE ArtistID='$ArtistID'"); +if($DB->record_count() == 0) { error(404); } +$Releases = $DB->to_array('GroupID',MYSQLI_ASSOC,false); +$GroupIDs = array_keys($Releases); + +$SQL = "SELECT CASE "; + +foreach ($_REQUEST['list'] as $Priority => $Selection) { + if(!is_number($Priority)) { + continue; + } + $SQL .= "WHEN "; + switch ($Selection) { + case '00': $SQL .= "t.Format='MP3' AND t.Encoding='V0 (VBR)'"; break; + case '01': $SQL .= "t.Format='MP3' AND t.Encoding='APX (VBR)'"; break; + case '02': $SQL .= "t.Format='MP3' AND t.Encoding='256 (VBR)'"; break; + case '03': $SQL .= "t.Format='MP3' AND t.Encoding='V1 (VBR)'"; break; + case '10': $SQL .= "t.Format='MP3' AND t.Encoding='224 (VBR)'"; break; + case '11': $SQL .= "t.Format='MP3' AND t.Encoding='V2 (VBR)'"; break; + case '12': $SQL .= "t.Format='MP3' AND t.Encoding='APS (VBR)'"; break; + case '13': $SQL .= "t.Format='MP3' AND t.Encoding='192 (VBR)'"; break; + case '20': $SQL .= "t.Format='MP3' AND t.Encoding='320'"; break; + case '21': $SQL .= "t.Format='MP3' AND t.Encoding='256'"; break; + case '22': $SQL .= "t.Format='MP3' AND t.Encoding='224'"; break; + case '23': $SQL .= "t.Format='MP3' AND t.Encoding='192'"; break; + case '30': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='Vinyl'"; break; + case '31': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='DVD'"; break; + case '32': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='SACD'"; break; + case '33': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='WEB'"; break; + case '34': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless' AND HasLog='1' AND LogScore='100' AND HasCue='1'"; break; + case '35': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless' AND HasLog='1' AND LogScore='100'"; break; + case '36': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless' AND HasLog='1'"; break; + case '37': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless'"; break; + case '40': $SQL .= "t.Format='DTS'"; break; + case '41': $SQL .= "t.Format='Ogg Vorbis'"; break; + case '42': $SQL .= "t.Format='AAC' AND t.Encoding='320'"; break; + case '43': $SQL .= "t.Format='AAC' AND t.Encoding='256'"; break; + case '44': $SQL .= "t.Format='AAC' AND t.Encoding='q5.5'"; break; + case '45': $SQL .= "t.Format='AAC' AND t.Encoding='q5'"; break; + case '46': $SQL .= "t.Format='AAC' AND t.Encoding='192'"; break; + default: error(0); + } + $SQL .= " THEN $Priority "; +} +$SQL .= "ELSE 100 END AS Rank, +t.GroupID, +t.ID, +t.Media, +t.Format, +t.Encoding, +tg.ReleaseType, +IF(t.RemasterYear=0,tg.Year,t.RemasterYear), +tg.Name, +t.Size +FROM torrents AS t +JOIN torrents_group AS tg ON tg.ID=t.GroupID AND tg.CategoryID='1' AND tg.ID IN (".implode(',',$GroupIDs).") +ORDER BY t.GroupID ASC, Rank DESC, t.$Preference"; + +$DB->query($SQL); +$Downloads = $DB->to_array('1',MYSQLI_NUM,false); +$Artists = get_artists($GroupIDs, false); +$Skips = array(); +$TotalSize = 0; +if(count($Downloads)) { + foreach($Downloads as $Download) { + $TorrentIDs[] = $Download[2]; + } + $DB->query("SELECT TorrentID, file FROM torrents_files WHERE TorrentID IN (".implode(',', $TorrentIDs).")"); + $Torrents = $DB->to_array('TorrentID',MYSQLI_ASSOC,false); +} + +require(SERVER_ROOT.'/classes/class_torrent.php'); +require(SERVER_ROOT.'/classes/class_zip.php'); +$Zip = new ZIP(file_string($ArtistName)); +foreach($Downloads as $Download) { + list($Rank, $GroupID, $TorrentID, $Media, $Format, $Encoding, $ReleaseType, $Year, $Album, $Size) = $Download; + $Artist = display_artists($Artists[$GroupID],false,true,false); + if ($Rank == 100) { + $Skips[] = $Artist.$Album.' '.$Year; + continue; + } + if($Releases[$GroupID]['Importance'] == 1) { + $ReleaseTypeName = $ReleaseTypes[$ReleaseType]; + } elseif($Releases[$GroupID]['Importance'] == 2) { + $ReleaseTypeName = "Guest Appearance"; + } elseif($Releases[$GroupID]['Importance'] == 3) { + $ReleaseTypeName = "Remixed By"; + } + $TotalSize += $Size; + $Contents = unserialize(base64_decode($Torrents[$TorrentID]['file'])); + $Tor = new TORRENT($Contents, true); + $Tor->set_announce_url(ANNOUNCE_URL.'/'.$LoggedUser['torrent_pass'].'/announce'); + unset($Tor->Val['announce-list']); + + // We need this section for long file names :/ + $TorrentName=''; + $TorrentInfo=''; + $TorrentName = file_string($Artist.$Album); + if ($Year > 0) { $TorrentName.=' - '.file_string($Year); } + if ($Media != '') { $TorrentInfo .= file_string($Media); } + if ($Format != '') { + if ($TorrentInfo!='') { $TorrentInfo .= ' - '; } + $TorrentInfo .= file_string($Format); + } + if ($Encoding!='') { + if ($TorrentInfo != '') { $TorrentInfo.=' - '; } + $TorrentInfo .= file_string($Encoding); + } + if ($TorrentInfo != '') { $TorrentInfo = " ($TorrentInfo)"; } + if (strlen($TorrentName) + strlen($TorrentInfo) + 3 > 200) { + $TorrentName = file_string($Album).(($Year>0)?(' - '.file_string($Year)):''); + } + $FileName = cut_string($TorrentName.$TorrentInfo, 180, true, false); + + $Zip->add_file($Tor->enc(), $ReleaseTypeName.'/'.$FileName.'.torrent'); +} +$Analyzed = count($Downloads); +$Skipped = count($Skips); +$Downloaded = $Analyzed - $Skipped; +$Time = number_format(((microtime(true)-$ScriptStartTime)*1000),5).' ms'; +$Used = get_size(memory_get_usage(true)); +$Date = date('M d Y, H:i'); +$Zip->add_file('Collector Download Summary - '.SITE_NAME."\r\n\r\nUser:\t\t$LoggedUser[Username]\r\nPasskey:\t$LoggedUser[torrent_pass]\r\n\r\nTime:\t\t$Time\r\nUsed:\t\t$Used\r\nDate:\t\t$Date\r\n\r\nTorrents Analyzed:\t\t$Analyzed\r\nTorrents Filtered:\t\t$Skipped\r\nTorrents Downloaded:\t$Downloaded\r\n\r\nTotal Size of Torrents (Ratio Hit): ".get_size($TotalSize)."\r\n\r\nAlbums Unavailable within your criteria (consider making a request for your desired format):\r\n".implode("\r\n",$Skips), 'Summary.txt'); +$Settings = array(implode(':',$_REQUEST['list']),$_REQUEST['preference']); +$Zip->close_stream(); + +$Settings = array(implode(':',$_REQUEST['list']),$_REQUEST['preference']); +if(!isset($LoggedUser['Collector']) || $LoggedUser['Collector'] != $Settings) { + $DB->query("SELECT SiteOptions FROM users_info WHERE UserID='".$LoggedUser['ID']."'"); + list($Options) = $DB->next_record(MYSQLI_NUM,false); + $Options = unserialize($Options); + $Options['Collector'] = $Settings; + $DB->query("UPDATE users_info SET SiteOptions='".db_string(serialize($Options))."' WHERE UserID='$LoggedUser[ID]'"); + $Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']); + $Cache->insert('Collector',$Settings); + $Cache->commit_transaction(0); +} +?> diff --git a/sections/artist/edit.php b/sections/artist/edit.php new file mode 100644 index 00000000..260b79a9 --- /dev/null +++ b/sections/artist/edit.php @@ -0,0 +1,110 @@ +query("SELECT + Name, + Image, + Body, + VanityHouse + FROM artists_group AS a + LEFT JOIN wiki_artists ON wiki_artists.RevisionID=a.RevisionID + WHERE a.ArtistID='$ArtistID'"); + +if($DB->record_count() < 1) { + error("Cannot find the artist with the ID ".$ArtistID.': See the log.'); +} + +list($Name, $Image, $Body, $VanityHouse) = $DB->next_record(MYSQLI_NUM, true); + +// Start printing form +show_header('Edit artist'); +?> +
    +

    Edit

    +
    +
    + + + +
    +

    Image

    +
    +

    Artist info

    +
    +

    Vanity House />

    +

    Edit summary

    +
    +
    + +
    +
    +
    +
    + +

    Rename

    +
    +
    + + + +
    + +
    + +
    + +
    +
    +
    + + +

    Aliases

    +
    +
      + +query("SELECT AliasID, Name, UserID, Redirect FROM artists_alias WHERE ArtistID='$ArtistID'"); + while(list($AliasID, $AliasName, $User, $Redirect) = $DB->next_record(MYSQLI_NUM, true)) { + if($AliasName == $Name) { $DefaultRedirectID = $AliasID; } +?> +
    • . + User. (writes redirect to ) + [X] +
    • + +
    +
    +
    + + + +

    Name:

    +
    +

    Writes redirect to (Alias ID, blank for no redirect):

    +
    + This redirects artist names as they are written, eg. new torrents and added artists. All uses of this new alias will be redirected to the alias ID you enter here. Use for common misspellings, etc.
    + + +
    +
    +
    + + + +
    + diff --git a/sections/artist/history.php b/sections/artist/history.php new file mode 100644 index 00000000..072de78c --- /dev/null +++ b/sections/artist/history.php @@ -0,0 +1,36 @@ +query("SELECT Name FROM artists_group WHERE ArtistID='$ArtistID'"); +list($Name) = $DB->next_record(MYSQLI_NUM, true); + +show_header("Revision history for ".$Name); // Set title + +// Start printing form +?> +
    +

    Revision history for

    +revision_history(); // the wiki class takes over from here +?> +
    + diff --git a/sections/artist/index.php b/sections/artist/index.php new file mode 100644 index 00000000..7e50b843 --- /dev/null +++ b/sections/artist/index.php @@ -0,0 +1,99 @@ +query("SELECT ArtistID FROM artists_alias WHERE Name LIKE '$Name'"); + if(list($ID) = $DB->next_record(MYSQLI_NUM, false)) { + header('Location: artist.php?id='.$ID); + die(); + } else { + if(isset($LoggedUser['SearchType']) && $LoggedUser['SearchType']) { + header('Location: torrents.php?action=advanced&artistname='.urlencode($_GET['artistname'])); + } else { + header('Location: torrents.php?searchstr='.urlencode($_GET['artistname'])); + } + die(); + } + } else { + header('Location: torrents.php'); + } +} +?> diff --git a/sections/artist/notify.php b/sections/artist/notify.php new file mode 100644 index 00000000..737bb5b0 --- /dev/null +++ b/sections/artist/notify.php @@ -0,0 +1,31 @@ +query("SELECT GROUP_CONCAT(Name SEPARATOR '|') FROM artists_alias WHERE ArtistID = '$ArtistID' AND Redirect = 0 GROUP BY ArtistID"); +list($ArtistAliases) = $DB->next_record(MYSQLI_NUM, FALSE); + +$Notify = $Cache->get_value('notify_artists_'.$LoggedUser['ID']); +if(empty($Notify)) { + $DB->query("SELECT ID, Artists FROM users_notify_filters WHERE Label='Artist notifications' AND UserID='$LoggedUser[ID]' ORDER BY ID LIMIT 1"); +} else { + $DB->query("SELECT ID, Artists FROM users_notify_filters WHERE ID='$Notify[ID]'"); +} +if(empty($Notify) && $DB->record_count() == 0) { + $DB->query("INSERT INTO users_notify_filters (UserID, Label, Artists) VALUES ('$LoggedUser[ID]', 'Artist notifications', '|".db_string($ArtistAliases)."|')"); + $FilterID = $DB->inserted_id(); + $Cache->delete_value('notify_filters_'.$LoggedUser['ID']); + $Cache->delete_value('notify_artists_'.$LoggedUser['ID']); +} else { + list($ID, $ArtistNames) = $DB->next_record(MYSQLI_NUM, FALSE); + if(stripos($ArtistNames,$ArtistAliases) === FALSE) { + $ArtistNames.=$ArtistAliases.'|'; + $DB->query("UPDATE users_notify_filters SET Artists='".db_string($ArtistNames)."' WHERE ID='$ID'"); + $Cache->delete_value('notify_filters_'.$LoggedUser['ID']); + $Cache->delete_value('notify_artists_'.$LoggedUser['ID']); + } +} +header('Location: '.$_SERVER['HTTP_REFERER']); +?> diff --git a/sections/artist/notifyremove.php b/sections/artist/notifyremove.php new file mode 100644 index 00000000..81827bea --- /dev/null +++ b/sections/artist/notifyremove.php @@ -0,0 +1,27 @@ +get_value('notify_artists_'.$LoggedUser['ID'])) === FALSE) { + $DB->query("SELECT ID, Artists FROM users_notify_filters WHERE Label='Artist notifications' AND UserID='$LoggedUser[ID]' ORDER BY ID LIMIT 1"); +} else { + $DB->query("SELECT ID, Artists FROM users_notify_filters WHERE ID='$Notify[ID]'"); +} +list($ID,$Artists) = $DB->next_record(MYSQLI_NUM, FALSE); +$DB->query("SELECT Name FROM artists_alias WHERE ArtistID = '$ArtistID' AND Redirect=0"); +while(list($Alias) = $DB->next_record(MYSQLI_NUM, FALSE)) { + while(stripos($Artists, '|'.$Alias.'|') !== FALSE) { + $Artists = str_ireplace('|'.$Alias.'|', '|', $Artists); + } +} +if($Artists == '|') { + $DB->query("DELETE FROM users_notify_filters WHERE ID=$ID"); +} else { + $DB->query("UPDATE users_notify_filters SET Artists='".db_string($Artists)."' WHERE ID='$ID'"); +} +$Cache->delete_value('notify_filters_'.$LoggedUser['ID']); +$Cache->delete_value('notify_artists_'.$LoggedUser['ID']); +header('Location: '.$_SERVER['HTTP_REFERER']); +?> diff --git a/sections/artist/rename.php b/sections/artist/rename.php new file mode 100644 index 00000000..4daa4853 --- /dev/null +++ b/sections/artist/rename.php @@ -0,0 +1,147 @@ +query("SELECT Name FROM artists_group WHERE ArtistID='$ArtistID'"); +if($DB->record_count()==0) { error(404); } +list($OldName) = $DB->next_record(MYSQLI_NUM, false); +if($OldName == $NewName) { error('The new name is identical to the old name.'); } + +$DB->query("SELECT AliasID FROM artists_alias WHERE Name='".db_string($OldName)."' AND ArtistID='$ArtistID'"); +list($OldAliasID) = $DB->next_record(MYSQLI_NUM, false); +if(!$OldAliasID) { error('Could not find old alias ID'); } + +$DB->query("SELECT AliasID, ArtistID FROM artists_alias WHERE name LIKE '".db_string($NewName, true)."'"); +list($TargetAliasID, $TargetArtistID) = $DB->next_record(MYSQLI_NUM, false); + +if(!$TargetAliasID || $TargetAliasID==$OldAliasID) { + // no merge, just rename + $DB->query("INSERT INTO artists_alias (ArtistID, Name, Redirect, UserID) VALUES ($ArtistID, '".db_string($NewName)."', '0', '$LoggedUser[ID]')"); + $TargetAliasID = $DB->inserted_id(); + + $DB->query("UPDATE artists_alias SET Redirect='$TargetAliasID' WHERE AliasID='$OldAliasID'"); + $DB->query("UPDATE artists_group SET Name='".db_string($NewName)."' WHERE ArtistID='$ArtistID'"); + + $DB->query("SELECT GroupID FROM torrents_artists WHERE AliasID='$OldAliasID'"); + $Groups = $DB->collect('GroupID'); + $DB->query("UPDATE IGNORE torrents_artists SET AliasID='$TargetAliasID' WHERE AliasID='$OldAliasID'"); + $DB->query("DELETE FROM torrents_artists WHERE AliasID='$OldAliasID'"); + if(!empty($Groups)) { + foreach($Groups as $GroupID) { + $Cache->delete_value('groups_artists_'.$GroupID); // Delete group artist cache + update_hash($GroupID); + } + } + + $DB->query("SELECT RequestID FROM requests_artists WHERE AliasID='$OldAliasID'"); + $Requests = $DB->collect('RequestID'); + $DB->query("UPDATE IGNORE requests_artists SET AliasID='$TargetAliasID' WHERE AliasID='$OldAliasID'"); + $DB->query("DELETE FROM requests_artists WHERE AliasID='$OldAliasID'"); + if(!empty($Requests)) { + foreach($Requests as $RequestID) { + $Cache->delete_value('request_artists_'.$RequestID); // Delete group artist cache + update_sphinx_requests($RequestID); + } + } + $TargetArtistID = $ArtistID; + +} else { // Merge stuff + $DB->query("UPDATE artists_alias SET Redirect='$TargetAliasID',ArtistID='$TargetArtistID' WHERE AliasID='$OldAliasID'"); + $DB->query("UPDATE artists_alias SET Redirect='0' WHERE AliasID='$TargetAliasID'"); + if($ArtistID != $TargetArtistID) { + $DB->query("UPDATE artists_alias SET ArtistID='$TargetArtistID' WHERE ArtistID='$ArtistID'"); + $DB->query("DELETE FROM artists_group WHERE ArtistID='$ArtistID'"); + } else { + $DB->query("UPDATE artists_group SET Name='".db_string($NewName)."' WHERE ArtistID='$ArtistID'"); + } + + $DB->query("SELECT GroupID FROM torrents_artists WHERE AliasID='$OldAliasID'"); + $Groups = $DB->collect('GroupID'); + $DB->query("UPDATE IGNORE torrents_artists SET AliasID='$TargetAliasID',ArtistID='$TargetArtistID' WHERE AliasID='$OldAliasID'"); + $DB->query("DELETE FROM torrents_artists WHERE AliasID='$OldAliasID'"); + if(!empty($Groups)) { + foreach($Groups as $GroupID) { + $Cache->delete_value('groups_artists_'.$GroupID); + update_hash($GroupID); + } + } + + $DB->query("SELECT RequestID FROM requests_artists WHERE AliasID='$OldAliasID'"); + $Requests = $DB->collect('RequestID'); + $DB->query("UPDATE IGNORE requests_artists SET AliasID='$TargetAliasID',ArtistID='$TargetArtistID' WHERE AliasID='$OldAliasID'"); + $DB->query("DELETE FROM requests_artists WHERE AliasID='$OldAliasID'"); + if(!empty($Requests)) { + foreach($Requests as $RequestID) { + $Cache->delete_value('request_artists_'.$RequestID); + update_sphinx_requests($RequestID); + } + } + + if($ArtistID != $TargetArtistID) { + $DB->query("SELECT GroupID FROM torrents_artists WHERE ArtistID='$ArtistID'"); + $Groups = $DB->collect('GroupID'); + $DB->query("UPDATE IGNORE torrents_artists SET ArtistID='$TargetArtistID' WHERE ArtistID='$ArtistID'"); + $DB->query("DELETE FROM torrents_artists WHERE ArtistID='$ArtistID'"); + if(!empty($Groups)) { + foreach($Groups as $GroupID) { + $Cache->delete_value('groups_artists_'.$GroupID); + update_hash($GroupID); + } + } + + $DB->query("SELECT RequestID FROM requests_artists WHERE ArtistID='$ArtistID'"); + $Requests = $DB->collect('RequestID'); + $DB->query("UPDATE IGNORE requests_artists SET ArtistID='$TargetArtistID' WHERE ArtistID='$ArtistID'"); + $DB->query("DELETE FROM requests_artists WHERE ArtistID='$ArtistID'"); + if(!empty($Requests)) { + foreach($Requests as $RequestID) { + $Cache->delete_value('request_artists_'.$RequestID); + update_sphinx_requests($RequestID); + } + } + } +} + +$Cache->delete_value('artist_'.$ArtistID); + +// Clear torrent caches +$DB->query("SELECT GroupID FROM torrents_artists WHERE ArtistID='$ArtistID'"); +while(list($GroupID) = $DB->next_record()) { + $Cache->delete_value('torrents_details_'.$GroupID); +} + +$Cache->delete_value('artist_'.$ArtistID); +$Cache->delete_value('artist_'.$TargetArtistID); +$Cache->delete_value('artists_requests_'.$TargetArtistID); +$Cache->delete_value('artists_requests_'.$ArtistID); + +header('Location: artist.php?id='.$TargetArtistID); + +?> diff --git a/sections/artist/takeedit.php b/sections/artist/takeedit.php new file mode 100644 index 00000000..aaf0d2b8 --- /dev/null +++ b/sections/artist/takeedit.php @@ -0,0 +1,58 @@ +query("INSERT INTO wiki_artists (PageID, Body, Image, UserID, Summary, Time) + VALUES ('$ArtistID', '$Body', '$Image', '$UserID', '$Summary', '".sqltime()."')"); +} else { // revert + $DB->query("INSERT INTO wiki_artists (PageID, Body, Image, UserID, Summary, Time) + SELECT '$ArtistID', Body, Image, '$UserID', 'Reverted to revision $RevisionID', '".sqltime()."' + FROM wiki_artists WHERE RevisionID='$RevisionID'"); +} + +$RevisionID=$DB->inserted_id(); + +// Update artists table (technically, we don't need the RevisionID column, but we can use it for a join which is nice and fast) +$DB->query("UPDATE artists_group + SET + ". ( isset($VanityHouse) ? "VanityHouse='$VanityHouse'," : '' ) ." + RevisionID='$RevisionID' + WHERE ArtistID='$ArtistID'"); + +// There we go, all done! +$Cache->delete_value('artist_'.$ArtistID); // Delete artist cache +header('Location: artist.php?id='.$ArtistID); +?> \ No newline at end of file diff --git a/sections/artist/vote_similar.php b/sections/artist/vote_similar.php new file mode 100644 index 00000000..a3b41eed --- /dev/null +++ b/sections/artist/vote_similar.php @@ -0,0 +1,28 @@ +query("SELECT SimilarID FROM artists_similar_votes WHERE SimilarID='$SimilarID' AND UserID='$UserID' AND Way='$Way'"); +if($DB->record_count() == 0) { + if($Way == 'down') { + $Score = 'Score-100'; + } elseif($Way == 'up') { + $Score = 'Score+100'; + } else { // Nothing is impossible! + $Score = 'Score'; + } + $DB->query("UPDATE artists_similar_scores SET Score=$Score WHERE SimilarID='$SimilarID'"); + $DB->query("INSERT iNTO artists_similar_votes (SimilarID, UserID, Way) VALUES ('$SimilarID', '$UserID', '$Way')"); + $Cache->delete_value('artist_'.$ArtistID); // Delete artist cache +} +header('Location: '.$_SERVER['HTTP_REFERER']); +?> diff --git a/sections/better/better.php b/sections/better/better.php new file mode 100644 index 00000000..6cad4848 --- /dev/null +++ b/sections/better/better.php @@ -0,0 +1,101 @@ + +
    +

    Pursuit of Perfection

    +
    +

    Here at What, we believe that there's always room for improvement, and to aid our effort in the pursuit of perfection we've put together a few simple lists that can help you build ratio, and help us improve our overall quality. Each list features 100 torrents at a time and updates every 15 minutes.

    +
    +

    Lists

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MethodAdditional Info
    + Transcoding V0 + + When a perfect lossless rip is available and we don't have the 'perfect 3'. +
    + Transcoding V2 + + When a perfect lossless rip is available and we don't have the 'perfect 3'. +
    + Transcoding 320 + + When a perfect lossless rip is available and we don't have the 'perfect 3'. +
    + Transcoding All + + When a perfect lossless rip is available and we don't have any of the 'perfect 3' +
    + Snatch + + Torrents you've already downloaded that can be transcoded. +
    + Upload + + Torrents you've uploaded that could be improved. +
    + Tags + + Torrents that have been marked as having 'Very bad tags' or 'No tags at all'. +
    + Folder Names + + Torrents that have been marked as having 'Very bad folder names' or 'No folder names at all'. +
    + File Names + + Torrents that have been marked as having 'Bad File Names'. +
    + Single seeded FLAC torrents + + FLAC torrents that only have one seeder, show them some love! +
    +
    +
    + diff --git a/sections/better/files.php b/sections/better/files.php new file mode 100644 index 00000000..7f2c77b3 --- /dev/null +++ b/sections/better/files.php @@ -0,0 +1,88 @@ +query("DELETE FROM torrents_bad_files WHERE TorrentID = ".$_GET['remove']); + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$_GET['remove']); + list($GroupID) = $DB->next_record(); + $Cache->delete_value('torrents_details_'.$GroupID); +} + + +if(!empty($_GET['filter']) && $_GET['filter'] == "all") { + $Join = ""; + $All = true; +} else { + $Join = "JOIN xbt_snatched as x ON x.fid=tfi.TorrentID AND x.uid = ".$LoggedUser['ID']; + $All = false; +} + +show_header('Torrents with bad file names'); +$DB->query("SELECT tfi.TorrentID, t.GroupID FROM torrents_bad_files AS tfi JOIN torrents AS t ON t.ID = tfi.TorrentID ".$Join." ORDER BY tfi.TimeAdded ASC"); +$TorrentsInfo = $DB->to_array('TorrentID', MYSQLI_ASSOC); +foreach($TorrentsInfo as $Torrent) { + $GroupIDs[] = $Torrent['GroupID']; +} +$Results = get_groups($GroupIDs); +$Results = $Results['matches']; +?> + + + +

    All torrents trumpable for bad file names

    + +

    Torrents trumpable for bad file names, that you've snatched

    + + +
    +

    There are torrents remaining

    + + $Info) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TorrentTags, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Results[$Info['GroupID']]); + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + + $ExtraInfo = torrent_info($Torrents[$TorrentID]); + if($ExtraInfo) { + $DisplayName.=' - '.$ExtraInfo; + } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + +
    + [DL] + + [X] + + +
    +
    + diff --git a/sections/better/folders.php b/sections/better/folders.php new file mode 100644 index 00000000..d79dd8da --- /dev/null +++ b/sections/better/folders.php @@ -0,0 +1,89 @@ +query("DELETE FROM torrents_bad_folders WHERE TorrentID = ".$_GET['remove']); + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$_GET['remove']); + list($GroupID) = $DB->next_record(); + $Cache->delete_value('torrents_details_'.$GroupID); +} + + +if(!empty($_GET['filter']) && $_GET['filter'] == "all") { + $Join = ""; + $All = true; +} else { + $Join = "JOIN xbt_snatched as x ON x.fid=tbf.TorrentID AND x.uid = ".$LoggedUser['ID']; + $All = false; +} + +show_header('Torrents with bad folder names'); +$DB->query("SELECT tbf.TorrentID, t.GroupID FROM torrents_bad_folders AS tbf JOIN torrents AS t ON t.ID = tbf.TorrentID ".$Join." ORDER BY tbf.TimeAdded ASC"); +$TorrentsInfo = $DB->to_array('TorrentID', MYSQLI_ASSOC); +foreach($TorrentsInfo as $Torrent) { + $GroupIDs[] = $Torrent['GroupID']; +} +$Results = get_groups($GroupIDs); +$Results = $Results['matches']; +?> + + + +

    All torrents trumpable for folder names

    + +

    Torrents trumpable for folder names, that you've snatched

    + + +
    +

    There are torrents remaining

    + + $Info) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TorrentTags, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Results[$Info['GroupID']]); + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { + $DisplayName.=" [".$GroupYear."]"; + } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + $ExtraInfo = torrent_info($Torrents[$TorrentID]); + if($ExtraInfo) { + $DisplayName.=' - '.$ExtraInfo; + } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + +
    + [DL] + + [X] + + +
    +
    + diff --git a/sections/better/index.php b/sections/better/index.php new file mode 100644 index 00000000..0e021cd0 --- /dev/null +++ b/sections/better/index.php @@ -0,0 +1,38 @@ + diff --git a/sections/better/single.php b/sections/better/single.php new file mode 100644 index 00000000..8304321b --- /dev/null +++ b/sections/better/single.php @@ -0,0 +1,63 @@ +get_value('better_single_groupids')) === false) { + $DB->query("SELECT t.ID AS TorrentID, + t.GroupID AS GroupID + FROM xbt_files_users AS x + JOIN torrents AS t ON t.ID=x.fid + WHERE t.Format='FLAC' + GROUP BY x.fid + HAVING COUNT(x.uid) = 1 + ORDER BY t.LogScore DESC, t.Time ASC LIMIT 30"); + + $GroupIDs = $DB->to_array('GroupID'); + $Cache->cache_value('better_single_groupids', $GroupIDs, 30*60); +} + +$Results = get_groups(array_keys($GroupIDs)); + +show_header('Single seeder FLACs'); +?> +
    + + + + +$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TorrentTags, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Group); + $FlacID = $GroupIDs[$GroupID]['TorrentID']; + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + + + +
    Torrent
    + + [DL] + +
    +
    + diff --git a/sections/better/snatch.php b/sections/better/snatch.php new file mode 100644 index 00000000..f2a0b4e9 --- /dev/null +++ b/sections/better/snatch.php @@ -0,0 +1,120 @@ +query("SELECT t.GroupID, x.fid + FROM ".($SeedingOnly ? 'xbt_files_users' : 'xbt_snatched')." AS x + JOIN torrents AS t ON t.ID=x.fid + WHERE t.Format='FLAC' + AND ((t.LogScore = '100' AND t.Media = 'CD') + OR t.Media = 'Vinyl') + AND x.uid='$UserID'"); + +$SnatchedGroupIDs = $DB->collect('GroupID'); +$Snatches = $DB->to_array('GroupID'); + +if(count($SnatchedGroupIDs) == 0) { error(($SeedingOnly ? "You aren't seeding any 100% FLACs!" : "You haven't snatched any 100% FLACs!")); } +// Create hash table + +$DB->query("CREATE TEMPORARY TABLE temp_sections_better_snatch + SELECT t.GroupID, + GROUP_CONCAT(t.Encoding SEPARATOR ' ') AS EncodingList + FROM torrents AS t + WHERE t.GroupID IN(".implode(',',$SnatchedGroupIDs).") + GROUP BY t.GroupID"); + +//$DB->query('SELECT * FROM t'); + +$DB->query("SELECT GroupID FROM temp_sections_better_snatch + WHERE EncodingList NOT LIKE '%V0 (VBR)%' + OR EncodingList NOT LIKE '%V2 (VBR)%' + OR EncodingList NOT LIKE '%320%'"); + +$GroupIDs = $DB->collect('GroupID'); + +if(count($GroupIDs) == 0) { error('No results found'); } + +$Results = get_groups($GroupIDs); + +show_header('Transcode Snatches'); +?> + +
    + + + + + + + +$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TorrentTags, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Group); + $FlacID = $Snatches[$GroupID]['fid']; + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + + $MissingEncodings = array('V0 (VBR)'=>1, 'V2 (VBR)'=>1, '320'=>1); + + foreach($Torrents as $Torrent) { + if(!empty($MissingEncodings[$Torrent['Encoding']])) { + $MissingEncodings[$Torrent['Encoding']] = 0; + } + } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + + + + + + +
    TorrentV2V0320
    + + [DL] + + YES':'NO'?>YES':'NO'?>YES':'NO'?>
    +
    + diff --git a/sections/better/tags.php b/sections/better/tags.php new file mode 100644 index 00000000..cc996b71 --- /dev/null +++ b/sections/better/tags.php @@ -0,0 +1,88 @@ +query("DELETE FROM torrents_bad_tags WHERE TorrentID = ".$_GET['remove']); + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$_GET['remove']); + list($GroupID) = $DB->next_record(); + $Cache->delete_value('torrents_details_'.$GroupID); +} + + +if(!empty($_GET['filter']) && $_GET['filter'] == "all") { + $Join = ""; + $All = true; +} else { + $Join = "JOIN xbt_snatched as x ON x.fid=tbt.TorrentID AND x.uid = ".$LoggedUser['ID']; + $All = false; +} + +show_header('Torrents with bad tags'); +$DB->query("SELECT tbt.TorrentID, t.GroupID FROM torrents_bad_tags AS tbt JOIN torrents AS t ON t.ID = tbt.TorrentID ".$Join." ORDER BY tbt.TimeAdded ASC"); +$TorrentsInfo = $DB->to_array('TorrentID', MYSQLI_ASSOC); +foreach($TorrentsInfo as $Torrent) { + $GroupIDs[] = $Torrent['GroupID']; +} +$Results = get_groups($GroupIDs); +$Results = $Results['matches']; +?> + + + +

    All torrents trumpable for tags

    + +

    Torrents trumpable for tags, that you've snatched

    + + +
    +

    There are torrents remaining

    + + $Info) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TorrentTags, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Results[$Info['GroupID']]); + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { + $DisplayName.=" [".$GroupYear."]"; + } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + $ExtraInfo = torrent_info($Torrents[$TorrentID]); + if($ExtraInfo) { + $DisplayName.=' - '.$ExtraInfo; + } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + +
    + [DL] + + [X] + + +
    +
    + diff --git a/sections/better/transcode.php b/sections/better/transcode.php new file mode 100644 index 00000000..a7e29c52 --- /dev/null +++ b/sections/better/transcode.php @@ -0,0 +1,148 @@ + 3) { error(0); } + +$Options = array('v0','v2','320'); + +if ($_GET['type'] == 3) { + $List = "!(v0 | v2 | 320)"; +} else { + $List = '!'.$Options[$_GET['type']]; + if($_GET['type'] == 0) { + $_GET['type'] = '0'; + } else { + $_GET['type'] = display_str($_GET['type']); + } +} + +$Query = '@format FLAC @encoding '.$List; + +if(!empty($_GET['search'])) { + $Query.=' @(groupname,artistname,yearfulltext) '.$SS->EscapeString($_GET['search']); +} + +$SS->SetFilter('logscore', array(100)); +$SS->SetSortMode(SPH_SORT_EXTENDED, "@random"); +$SS->limit(0, TORRENTS_PER_PAGE); + +$SS->set_index(SPHINX_INDEX.' delta'); + +$Results = $SS->search($Query, '', 0, array(), '', ''); + +if(count($Results) == 0) { error('No results found!'); } +/* +// If some were fetched from memcached, get their artists +if(!empty($Results['matches'])) { // Fetch the artists for groups + $GroupIDs = array_keys($Results['matches']); + $Artists = get_artists($GroupIDs); + foreach($Artists as $GroupID=>$Data) { + if(!empty($Data[1])) { + $Results['matches'][$GroupID]['Artists']=$Data[1]; // Only use main artists + } + ksort($Results['matches'][$GroupID]); + } +} +*/ + // These ones were not found in the cache, run SQL +if(!empty($Results['notfound'])) { + $SQLResults = get_groups($Results['notfound']); + + if(is_array($SQLResults['notfound'])) { // Something wasn't found in the db, remove it from results + reset($SQLResults['notfound']); + foreach($SQLResults['notfound'] as $ID) { + unset($SQLResults['matches'][$ID]); + unset($Results['matches'][$ID]); + } + } + + // Merge SQL results with memcached results + foreach($SQLResults['matches'] as $ID=>$SQLResult) { + $Results['matches'][$ID] = array_merge($Results['matches'][$ID], $SQLResult); + ksort($Results['matches'][$ID]); + } +} + +$Results = $Results['matches']; + + +show_header('Transcode Search'); +?> +
    +
    +
    +
    + + + + + +
    Search: + + + +   + +
    +
    +
    + + + + + + + +$Data) { +$Debug->log_var($Data); + list($Artists, $GroupCatalogueNumber, $ExtendedArtists, $GroupID2, $GroupName, $GroupRecordLabel, $ReleaseType, $TorrentTags, $Torrents, $GroupVanityHouse, $GroupYear, $CategoryID, $FreeTorrent, $HasCue, $HasLog, $TotalLeechers, $LogScore, $ReleaseType, $ReleaseType, $TotalSeeders, $MaxSize, $TotalSnatched, $GroupTime) = array_values($Data); + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + $MissingEncodings = array('V0 (VBR)'=>1, 'V2 (VBR)'=>1, '320'=>1); + $FlacID = 0; + + foreach($Torrents as $Torrent) { + if(!empty($MissingEncodings[$Torrent['Encoding']])) { + $MissingEncodings[$Torrent['Encoding']] = 0; + } elseif($Torrent['Format'] == 'FLAC' && $FlacID == 0) { + $FlacID = $Torrent['ID']; + } + } + + if($_GET['type'] == '3' && in_array(0, $MissingEncodings)) { + continue; + } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + + + + + + +
    TorrentV2V0320
    + + [DL] + + YES':'NO'?>YES':'NO'?>YES':'NO'?>
    +
    + diff --git a/sections/better/upload.php b/sections/better/upload.php new file mode 100644 index 00000000..b21b7ce7 --- /dev/null +++ b/sections/better/upload.php @@ -0,0 +1,107 @@ +query("SELECT t.GroupID, t.ID + FROM torrents AS t + WHERE + t.Format='FLAC' + AND ((t.LogScore = '100' AND t.Media = 'CD') + OR t.Media = 'Vinyl') + AND t.UserID='$UserID'"); + +$UploadedGroupIDs = $DB->collect('GroupID'); +$Uploads = $DB->to_array('GroupID'); + +if(count($UploadedGroupIDs) == 0) { error('You haven\'t uploaded any 100% flacs!'); } +// Create hash table + +$DB->query("CREATE TEMPORARY TABLE temp_sections_better_upload + SELECT t.GroupID, + GROUP_CONCAT(t.Encoding SEPARATOR ' ') AS EncodingList + FROM torrents AS t + WHERE t.GroupID IN(".implode(',',$UploadedGroupIDs).") + GROUP BY t.GroupID"); + +//$DB->query('SELECT * FROM t'); + +$DB->query("SELECT GroupID FROM temp_sections_better_upload + WHERE EncodingList NOT LIKE '%V0 (VBR)%' + OR EncodingList NOT LIKE '%V2 (VBR)%' + OR EncodingList NOT LIKE '%320%'"); + +$GroupIDs = $DB->collect('GroupID'); + +if(count($GroupIDs) == 0) { error('No results found'); } + +$Results = get_groups($GroupIDs); + +show_header('Transcode Uploads'); +?> +
    + + + + + + + +$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TorrentTags, $ReleaseType, $GroupVanityHouse, $Torrents, $Artists) = array_values($Group); + $FlacID = $Uploads[$GroupID]['ID']; + + $DisplayName = ''; + if(count($Artists)>0) { + $DisplayName = display_artists(array('1'=>$Artists)); + } + $DisplayName.=''.$GroupName.''; + if($GroupYear>0) { $DisplayName.=" [".$GroupYear."]"; } + if($ReleaseType>0) { $DisplayName.=" [".$ReleaseTypes[$ReleaseType]."]"; } + + $MissingEncodings = array('V0 (VBR)'=>1, 'V2 (VBR)'=>1, '320'=>1); + + foreach($Torrents as $Torrent) { + if(!empty($MissingEncodings[$Torrent['Encoding']])) { + $MissingEncodings[$Torrent['Encoding']] = 0; + } + } + + $TagList=array(); + if($TorrentTags!='') { + $TorrentTags=explode(' ',$TorrentTags); + foreach ($TorrentTags as $TagKey => $TagName) { + $TagName = str_replace('_','.',$TagName); + $TagList[]=''.$TagName.''; + } + $PrimaryTag = $TorrentTags[0]; + $TagList = implode(', ', $TagList); + $TorrentTags='
    '.$TagList.'
    '; + } +?> + + + + + + + +
    TorrentV2V0320
    + + [DL] + + YES':'NO'?>YES':'NO'?>YES':'NO'?>
    +
    + diff --git a/sections/blog/index.php b/sections/blog/index.php new file mode 100644 index 00000000..a3962db1 --- /dev/null +++ b/sections/blog/index.php @@ -0,0 +1,154 @@ +query("UPDATE blog SET ThreadID=NULL WHERE ID=".$_GET['id']); + $Cache->delete_value('blog'); + $Cache->delete_value('feed_blog'); + } + header('Location: blog.php'); + break; + case 'takeeditblog': + authorize(); + if(is_number($_POST['blogid']) && is_number($_POST['thread'])){ + $DB->query("UPDATE blog SET Title='".db_string($_POST['title'])."', Body='".db_string($_POST['body'])."', ThreadID=".$_POST['thread']." WHERE ID='".db_string($_POST['blogid'])."'"); + $Cache->delete_value('blog'); + $Cache->delete_value('feed_blog'); + } + header('Location: blog.php'); + break; + case 'editblog': + if(is_number($_GET['id'])){ + $BlogID = $_GET['id']; + $DB->query("SELECT Title, Body, ThreadID FROM blog WHERE ID=$BlogID"); + list($Title, $Body, $ThreadID) = $DB->next_record(); + } + break; + case 'deleteblog': + if(is_number($_GET['id'])){ + authorize(); + $DB->query("DELETE FROM blog WHERE ID='".db_string($_GET['id'])."'"); + $Cache->delete_value('blog'); + $Cache->delete_value('feed_blog'); + } + header('Location: blog.php'); + break; + + case 'takenewblog': + authorize(); + $Title = db_string($_POST['title']); + $Body = db_string($_POST['body']); + $ThreadID = $_POST['thread']; + if($ThreadID && is_number($ThreadID)) { + $DB->query("SELECT ForumID FROM forums_topics WHERE ID=".$ThreadID); + if($DB->record_count() < 1) { + error("No such thread exists!"); + header('Location: blog.php'); + } + } else { + $ThreadID = create_thread(ANNOUNCEMENT_FORUM_ID, $LoggedUser[ID], $Title, $Body); + if($ThreadID < 1) { + error(0); + } + } + + $DB->query("INSERT INTO blog (UserID, Title, Body, Time, ThreadID) VALUES ('$LoggedUser[ID]', '".db_string($_POST['title'])."', '".db_string($_POST['body'])."', '".sqltime()."', ".$ThreadID.")"); + $Cache->delete_value('blog'); + if(isset($_POST['subscribe'])) { + $DB->query("INSERT IGNORE INTO users_subscriptions VALUES ('$LoggedUser[ID]', $ThreadID)"); + $Cache->delete_value('subscriptions_user_'.$LoggedUser['ID']); + } + + header('Location: blog.php'); + break; + } + } + + ?> +
    +
    + +
    +
    +
    + + + + + +

    Title

    + />
    +

    Body

    +
    +

    Thread ID

    + /> + (Leave blank to create thread automatically) +

    + tabindex="2" /> + +
    + +
    +
    +
    +
    +
    + +
    +get_value('blog')) { + $DB->query("SELECT + b.ID, + um.Username, + b.Title, + b.Body, + b.Time, + b.ThreadID + FROM blog AS b LEFT JOIN users_main AS um ON b.UserID=um.ID + ORDER BY Time DESC + LIMIT 20"); + $Blog = $DB->to_array(); + $Cache->cache_value('Blog',$Blog,1209600); +} + +foreach ($Blog as $BlogItem) { + list($BlogID, $Author, $Title, $Body, $BlogTime, $ThreadID) = $BlogItem; +?> +
    +
    + - posted by + + - [Edit] + [Delete] + +
    +
    + full_format($Body)?> + +

    + Discuss this post here + + [Dead] + +
    +
    +
    + +
    + diff --git a/sections/bookmarks/add.php b/sections/bookmarks/add.php new file mode 100644 index 00000000..8ecd6b29 --- /dev/null +++ b/sections/bookmarks/add.php @@ -0,0 +1,64 @@ +query("SELECT UserID FROM $Table WHERE UserID='$LoggedUser[ID]' AND $Col='".db_string($_GET['id'])."'"); +if($DB->record_count() == 0) { + $DB->query("INSERT IGNORE INTO $Table + (UserID, $Col, Time) + VALUES + ('$LoggedUser[ID]', '".db_string($_GET['id'])."', '".sqltime()."')"); + $Cache->delete_value('bookmarks_'.$Type.'_'.$LoggedUser['ID']); + if ($Type == 'torrent') { + $Cache->delete_value('bookmarks_torrent_'.$LoggedUser['ID'].'_full'); + $GroupID = $_GET['id']; + + $DB->query("SELECT Name, Year, WikiBody, TagList FROM torrents_group WHERE ID = '$GroupID'"); + list($GroupTitle, $Year, $Body, $TagList) = $DB->next_record(); + $TagList = str_replace('_','.',$TagList); + + $DB->query("SELECT ID, Format, Encoding, HasLog, HasCue, LogScore, Media, Scene, FreeTorrent, UserID FROM torrents WHERE GroupID = '$GroupID'"); + // RSS feed stuff + while ($Torrent = $DB->next_record()) { + $Title = $GroupTitle; + list($TorrentID, $Format, $Bitrate, $HasLog, $HasCue, $LogScore, $Media, $Scene, $Freeleech, $UploaderID) = $Torrent; + $Title .= " [".$Year."] - "; + $Title .= $Format." / ".$Bitrate; + if ($HasLog == "'1'") { $Title .= " / Log"; } + if ($HasLog) { $Title .= " / ".$LogScore.'%'; } + if ($HasCue == "'1'") { $Title .= " / Cue"; } + $Title .= " / ".trim($Media); + if ($Scene == "1") { $Title .= " / Scene"; } + if ($Freeleech == "1") { $Title .= " / Freeleech!"; } + if ($Freeleech == "2") { $Title .= " / Neutral leech!"; } + + $UploaderInfo = user_info($UploaderID); + $Item = $Feed->item($Title, + $Text->strip_bbcode($Body), + 'torrents.php?action=download&authkey=[[AUTHKEY]]&torrent_pass=[[PASSKEY]]&id='.$TorrentID, + $UploaderInfo['Username'], + 'torrents.php?id='.$GroupID, + trim($TagList)); + $Feed->populate('torrents_bookmarks_t_'.$LoggedUser['torrent_pass'], $Item); + } + } elseif ($Type == 'request') { + $DB->query("SELECT UserID FROM $Table WHERE $Col='".db_string($_GET['id'])."'"); + $Bookmarkers = $DB->collect('UserID'); + $SS->UpdateAttributes('requests requests_delta', array('bookmarker'), array($_GET['id'] => array($Bookmarkers)), true); + } +} +?> diff --git a/sections/bookmarks/artists.php b/sections/bookmarks/artists.php new file mode 100644 index 00000000..4cc40bac --- /dev/null +++ b/sections/bookmarks/artists.php @@ -0,0 +1,95 @@ +query("SELECT Username FROM users_main WHERE ID='$UserID'"); + list($Username) = $DB->next_record(); +} else { + $UserID = $LoggedUser['ID']; +} + +$Sneaky = ($UserID != $LoggedUser['ID']); + +//$ArtistList = all_bookmarks('artist', $UserID); + +$DB->query('SELECT ag.ArtistID, ag.Name + FROM bookmarks_artists AS ba + INNER JOIN artists_group AS ag ON ba.ArtistID = ag.ArtistID + WHERE ba.UserID = '.$UserID.' + ORDER BY ag.Name'); + +$ArtistList = $DB->to_array(); + +$Title = ($Sneaky)?"$Username's bookmarked artists":'Your bookmarked artists'; + +show_header($Title,'browse'); + +?> +
    +

    + +
    + +

    You have not bookmarked any artists.

    +
    +
    + + + + + + + + + + +
    Artist
    + + +get_value('notify_artists_'.$LoggedUser['ID'])) === FALSE) { + $DB->query("SELECT ID, Artists FROM users_notify_filters WHERE UserID='$LoggedUser[ID]' AND Label='Artist notifications' LIMIT 1"); + $Notify = $DB->next_record(MYSQLI_ASSOC); + $Cache->cache_value('notify_artists_'.$LoggedUser['ID'], $Notify, 0); + } + if (stripos($Notify['Artists'], '|'.$Name.'|') === FALSE) { +?> + [Notify of new uploads] + + [Do not notify of new uploads] + + [Remove bookmark] + +
    + + +cache_value('bookmarks_'.$UserID, serialize(array(array($Username, $TorrentList, $CollageDataList))), 3600); +?> diff --git a/sections/bookmarks/functions.php b/sections/bookmarks/functions.php new file mode 100644 index 00000000..81daefb0 --- /dev/null +++ b/sections/bookmarks/functions.php @@ -0,0 +1,44 @@ +get_value($CacheKey)) === FALSE) { + list($Table, $Col) = bookmark_schema($Type); + $DB->query("SELECT $Col FROM $Table WHERE UserID = '$UserID'"); + $Bookmarks = $DB->collect($Col); + $Cache->cache_value($CacheKey, $Bookmarks, 0); + } + return $Bookmarks; +} +?> diff --git a/sections/bookmarks/index.php b/sections/bookmarks/index.php new file mode 100644 index 00000000..435c1f3e --- /dev/null +++ b/sections/bookmarks/index.php @@ -0,0 +1,53 @@ +query("DELETE b FROM bookmarks_torrents AS b WHERE b.UserID='".$LoggedUser['ID']."' AND b.GroupID IN(SELECT DISTINCT t.GroupID FROM torrents AS t INNER JOIN xbt_snatched AS s ON s.fid=t.ID AND s.uid='".$LoggedUser['ID']."')"); + $Cache->delete_value('bookmarks_torrent_'.$UserID); + $Cache->delete_value('bookmarks_torrent_'.$UserID.'_full'); + header('Location: bookmarks.php'); + die(); + break; + + case 'view': + if (empty($_REQUEST['type'])) { $_REQUEST['type'] = 'torrents'; } + switch ($_REQUEST['type']) { + case 'torrents': + require(SERVER_ROOT.'/sections/bookmarks/torrents.php'); + break; + case 'artists': + require(SERVER_ROOT.'/sections/bookmarks/artists.php'); + break; + case 'collages': + $_GET['bookmarks'] = 1; + require(SERVER_ROOT.'/sections/collages/browse.php'); + break; + case 'requests': + include(SERVER_ROOT.'/sections/requests/functions.php'); + $_GET['type'] = 'bookmarks'; + require(SERVER_ROOT.'/sections/requests/requests.php'); + break; + default: + error(404); + } + break; + default: + error(404); +} +?> diff --git a/sections/bookmarks/remove.php b/sections/bookmarks/remove.php new file mode 100644 index 00000000..56ba4eb0 --- /dev/null +++ b/sections/bookmarks/remove.php @@ -0,0 +1,23 @@ +query("DELETE FROM $Table WHERE UserID='".$LoggedUser['ID']."' AND $Col='".db_string($_GET['id'])."'"); +$Cache->delete_value('bookmarks_'.$Type.'_'.$UserID); +if ($Type == 'torrent') { + $Cache->delete_value('bookmarks_torrent_'.$UserID.'_full'); +} elseif ($Type == 'request') { + $DB->query("SELECT UserID FROM $Table WHERE $Col='".db_string($_GET['id'])."'"); + $Bookmarkers = $DB->collect('UserID'); + $SS->UpdateAttributes('requests requests_delta', array('bookmarker'), array($_GET['id'] => array($Bookmarkers)), true); +} +?> diff --git a/sections/bookmarks/torrents.php b/sections/bookmarks/torrents.php new file mode 100644 index 00000000..9b47b467 --- /dev/null +++ b/sections/bookmarks/torrents.php @@ -0,0 +1,423 @@ +query("SELECT Username FROM users_main WHERE ID='$UserID'"); + list($Username) = $DB->next_record(); +} else { + $UserID = $LoggedUser['ID']; +} + +$Sneaky = ($UserID != $LoggedUser['ID']); + +$Data = $Cache->get_value('bookmarks_torrent_'.$UserID.'_full'); + +if($Data) { + $Data = unserialize($Data); + list($K, list($TorrentList, $CollageDataList)) = each($Data); +} else { + // Build the data for the collage and the torrent list + $DB->query("SELECT + bt.GroupID, + tg.WikiImage, + tg.CategoryID, + bt.Time + FROM bookmarks_torrents AS bt + JOIN torrents_group AS tg ON tg.ID=bt.GroupID + WHERE bt.UserID='$UserID' + ORDER BY bt.Time"); + + $GroupIDs = $DB->collect('GroupID'); + $CollageDataList=$DB->to_array('GroupID', MYSQLI_ASSOC); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} + +$TokenTorrents = $Cache->get_value('users_tokens_'.$UserID); +if (empty($TokenTorrents)) { + $DB->query("SELECT TorrentID FROM users_freeleeches WHERE UserID=$UserID AND Expired=FALSE"); + $TokenTorrents = $DB->collect('TorrentID'); + $Cache->cache_value('users_tokens_'.$UserID, $TokenTorrents); +} + +$Title = ($Sneaky)?"$Username's bookmarked torrents":'Your bookmarked torrents'; + +// Loop through the result set, building up $Collage and $TorrentTable +// Then we print them. +$Collage = array(); +$TorrentTable = ''; + +$NumGroups = 0; +$Artists = array(); +$Tags = array(); + +foreach ($TorrentList as $GroupID=>$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists, $ExtendedArtists) = array_values($Group); + list($GroupID2, $Image, $GroupCategoryID, $AddedTime) = array_values($CollageDataList[$GroupID]); + + // Handle stats and stuff + $NumGroups++; + + if($GroupArtists) { + foreach($GroupArtists as $Artist) { + if(!isset($Artists[$Artist['id']])) { + $Artists[$Artist['id']] = array('name'=>$Artist['name'], 'count'=>1); + } else { + $Artists[$Artist['id']]['count']++; + } + } + } + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + $TorrentTags[]=''.$Tag.''; + } + $PrimaryTag = $TagList[0]; + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags='
    '.$TorrentTags.'
    '; + + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName = display_artists($ExtendedArtists); + } elseif(count($GroupArtists)>0) { + $DisplayName = display_artists(array('1'=>$GroupArtists)); + } else { + $DisplayName = ''; + } + $DisplayName .= ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + + // Start an output buffer, so we can store this output in $TorrentTable + ob_start(); + if(count($Torrents)>1 || $GroupCategoryID==1) { + // Grouped torrents + $ShowGroups = !(!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1); +?> + + +
    + +
    + + +
    + + + + + + Remove Bookmark +
    + + +
    +
    + + + $Torrent) { + + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if (in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent'])) { + $Torrent['PersonalFL'] = 1; + } + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) { + + $EditionID++; + if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) { + + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + +?> + + + + + + + + + + + [ DL + 0) && ($Torrent['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1')) { ?> + | FL + + | RP ] + +   »  + + + + > + + +'.$GroupName.''; + + if(!empty($Torrent['FreeTorrent'])) { + $DisplayName .=' Freeleech!'; + } elseif(in_array($TorrentID, $TokenTorrents)) { + $DisplayName .= 'Personal Freeleech!'; + } +?> + + + +
    +
    + + + + [ DL + 0) && ($Torrent['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1')) { ?> + | FL + + | RP ] + + + + + Remove Bookmark + + + + + + + > + + +0) { + $DisplayName .= display_artists(array('1'=>$GroupArtists), false); + } + $DisplayName .= $GroupName; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} +?> +
  15. + + + <?=$DisplayName?> + +
    + +
    +
  16. + +
    +

    RSS feed 

    + + +
    +

    You have not bookmarked any torrents.

    +
    +
    + + +
    + +
    +
    Cover Art
    +
      + +
    +
    + $CollageCovers) { ?> + + + +
    + + + + + + + + + + + +
    Torrents (View)SizeSnatchesSeedersLeechers
    +
    + +cache_value('bookmarks_torrent_'.$UserID.'_full', serialize(array(array($TorrentList, $CollageDataList))), 3600); +?> diff --git a/sections/captcha/index.php b/sections/captcha/index.php new file mode 100644 index 00000000..990ee639 --- /dev/null +++ b/sections/captcha/index.php @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/sections/chat/index.php b/sections/chat/index.php new file mode 100644 index 00000000..8915eaf8 --- /dev/null +++ b/sections/chat/index.php @@ -0,0 +1,121 @@ +query("SELECT IRCKey FROM users_main WHERE ID = $LoggedUser[ID]"); +list($IRCKey) = $DB->next_record(); + +if(empty($IRCKey)) { +?> +
    +

    IRC Rules - Please read these carefully!

    +
    +

    + Please set your IRC Key on your profile first! For more information on IRC, please read the wiki article. +

    +
    +
    + +
    +

    IRC Rules - Please read these carefully!

    +
    +
      +
    • + Staff have the final decision, if they say stop and you continue, expect at least to be banned from the IRC server. +
    • +
    • + Be respectful to IRC Operators and Administrators. These people are site staff who volunteer their time for little compensation. They are there for the benefit of all and to aid in conflict resolution, do not waste their time. +
    • +
    • + Do not link shock sites or anything NSFW (not safe for work) without a warning. If in doubt, ask a staff member in about it. +
    • +
    • + Excessive swearing will get you kicked, keep swearing to a minimum. +
    • +
    • + Do not leave your Caps Lock on all the time. It gets annoying, and you will likely get yourself kicked. +
    • +
    • + No arguing. You can't win an argument over the internet, so you're just wasting your time trying. +
    • +
    • + No prejudice, especially related to race, religion, politics, ethnic background, etc. It is highly suggested to avoid this entirely. +
    • +
    • + Flooding is irritating and will merit you a kick. This includes but is not limited to: automatic now playing scripts, pasting large amounts of text, and multiple consecutive lines with no relevance to the conversation at hand. +
    • +
    • + Impersonation of other members (particularly staff members) will not go unpunished. If you are uncertain of a users identity, check their vhost. +
    • +
    • + Spamming is strictly forbidden. This includes but is not limited to: personal sites, online auctions, and torrent uploads. +
    • +
    • + Obsessive annoyance both to other users and staff will not be tolerated. +
    • +
    • + Don't PM, DCC, or Query anyone you don't know or have never talked to without asking, this applies specifically to staff. +
    • +
    • + No language other than English is permitted in the official IRC channels. If we can't understand it, we can't moderate it. +
    • +
    • + The offering, selling, trading and giving away of invites to this or any other site on our IRC network is strictly forbidden. +
    • +
    • + Read the topic before asking questions. +
    • +
    +
    +
    +
    +
    + + +
    +
    + +
    +

    IRC

    +
    +
    +

    If you have an IRC client, visit this wiki entry for more information how to connect. (IRC Applet users are automatically identified with Drone.)

    +
    +
    + + + + + + + + + + + + + + +
    +
    +
    + diff --git a/sections/collages/add_comment.php b/sections/collages/add_comment.php new file mode 100644 index 00000000..8f982fea --- /dev/null +++ b/sections/collages/add_comment.php @@ -0,0 +1,20 @@ +query("INSERT INTO collages_comments + (CollageID, Body, UserID, Time) + VALUES + ('$CollageID', '".db_string($_POST['body'])."', '$LoggedUser[ID]', '".sqltime()."')"); + +$Cache->delete_value('collage_'.$CollageID.'_catalogue_0'); +$Cache->delete_value('collage_'.$CollageID); +header('Location: collages.php?id='.$CollageID); + +?> diff --git a/sections/collages/add_torrent.php b/sections/collages/add_torrent.php new file mode 100644 index 00000000..73082286 --- /dev/null +++ b/sections/collages/add_torrent.php @@ -0,0 +1,115 @@ +query("SELECT MAX(Sort) FROM collages_torrents WHERE CollageID='$CollageID'"); + list($Sort) = $DB->next_record(); + $Sort+=10; + + $DB->query("SELECT GroupID FROM collages_torrents WHERE CollageID='$CollageID' AND GroupID='$GroupID'"); + if($DB->record_count() == 0) { + $DB->query("INSERT IGNORE INTO collages_torrents + (CollageID, GroupID, UserID, Sort, AddedOn) + VALUES + ('$CollageID', '$GroupID', '$LoggedUser[ID]', '$Sort', NOW())"); + + $DB->query("UPDATE collages SET NumTorrents=NumTorrents+1 WHERE ID='$CollageID'"); + + $Cache->delete_value('collage_'.$CollageID); + $Cache->delete_value('torrents_details_'.$GroupID); + $Cache->delete_value('torrent_collages_'.$GroupID); + $Cache->delete_value('torrent_collages_personal_'.$GroupID); + + $DB->query("SELECT UserID FROM users_collage_subs WHERE CollageID=$CollageID"); + while (list($CacheUserID) = $DB->next_record()) { + $Cache->delete_value('collage_subs_user_new_'.$CacheUserID); + } + } +} + +$CollageID = $_POST['collageid']; +if(!is_number($CollageID)) { error(404); } +$DB->query("SELECT UserID, CategoryID, Locked, NumTorrents, MaxGroups, MaxGroupsPerUser FROM collages WHERE ID='$CollageID'"); +list($UserID, $CategoryID, $Locked, $NumTorrents, $MaxGroups, $MaxGroupsPerUser) = $DB->next_record(); +if($CategoryID == 0 && $UserID!=$LoggedUser['ID'] && !check_perms('site_collages_delete')) { error(403); } +if($Locked) { error(403); } +if($MaxGroups>0 && $NumTorrents>=$MaxGroups) { error(403); } +if($MaxGroupsPerUser>0) { + $DB->query("SELECT COUNT(ID) FROM collages_torrents WHERE CollageID='$CollageID' AND UserID='$LoggedUser[ID]'"); + if($DB->record_count()>=$MaxGroupsPerUser) { + error(403); + } +} + +if ($_REQUEST['action'] == 'add_torrent') { + $URLRegex = '/^https?:\/\/(www\.|ssl\.)?'.NONSSL_SITE_URL.'\/torrents\.php\?(page=[0-9]+&)?id=([0-9]+)/i'; + $Val->SetFields('url', '1','regex','The URL must be a link to a torrent on the site.',array('regex'=>$URLRegex)); + $Err = $Val->ValidateForm($_POST); + + if($Err) { + error($Err); + header('Location: collages.php?id='.$CollageID); + die(); + } + + $URL = $_POST['url']; + + // Get torrent ID + $URLRegex = '/torrents\.php\?(page=[0-9]+&)?id=([0-9]+)/i'; + preg_match($URLRegex, $URL, $Matches); + $TorrentID=$Matches[2]; + if(!$TorrentID || (int)$TorrentID == 0) { error(404); } + + $DB->query("SELECT ID FROM torrents_group WHERE ID='$TorrentID'"); + list($GroupID) = $DB->next_record(); + if(!$GroupID) { + error('The torrent was not found in the database.'); + } + + AddTorrent($CollageID, $GroupID); +} else { + $URLRegex = '/^https?:\/\/(www\.|ssl\.)?'.NONSSL_SITE_URL.'\/torrents\.php\?(page=[0-9]+&)?id=([0-9]+)/i'; + + $URLs = explode("\n",$_REQUEST['urls']); + $GroupIDs = array(); + $Err = ''; + + foreach ($URLs as $URL) { + $URL = trim($URL); + if ($URL == '') { continue; } + + $Matches = array(); + if (preg_match($URLRegex, $URL, $Matches)) { + $GroupIDs[] = $Matches[3]; + $GroupID = $Matches[3]; + } else { + $Err = "One of the entered URLs ($URL) does not correspond to a torrent on the site."; + break; + } + + $DB->query("SELECT ID FROM torrents_group WHERE ID='$GroupID'"); + if(!$DB->record_count()) { + $Err = "One of the entered URLs ($URL) does not correspond to a torrent on the site."; + break; + } + } + + if($Err) { + error($Err); + header('Location: collages.php?id='.$CollageID); + die(); + } + + foreach ($GroupIDs as $GroupID) { + AddTorrent($CollageID, $GroupID); + } +} + +header('Location: collages.php?id='.$CollageID); + +?> diff --git a/sections/collages/all_comments.php b/sections/collages/all_comments.php new file mode 100644 index 00000000..68c75d3f --- /dev/null +++ b/sections/collages/all_comments.php @@ -0,0 +1,131 @@ +get_value('collage_'.$CollageID.'_catalogue_'.$CatalogueID)) { + $DB->query("SELECT SQL_CALC_FOUND_ROWS + ID, + UserID, + Time, + Body + FROM collages_comments + WHERE CollageID = '$CollageID' + LIMIT $CatalogueLimit"); + $Catalogue = $DB->to_array(); + $DB->query("SELECT FOUND_ROWS()"); + list($Posts) = $DB->next_record(); + $Cache->cache_value('collage_'.$CollageID.'_catalogue_'.$CatalogueID, array($Catalogue,$Posts), 0); +} + +//This is a hybrid to reduce the catalogue down to the page elements: We use the page limit % catalogue +$Thread = array_slice($Catalogue,((POSTS_PER_PAGE*$Page-POSTS_PER_PAGE)%THREAD_CATALOGUE),POSTS_PER_PAGE,true); + +$DB->query("SELECT Name FROM collages WHERE ID='$CollageID'"); +list($Name) = $DB->next_record(); + +// Start printing +show_header('Comments for collage '.$Name, 'comments,bbcode'); +?> +
    +

    + Collages > + +

    + + + + + + + + + + + + +
    + # + by [Report Comment] + - [Quote] - [Edit] - [Delete] + + + + +
    + + <?=$Username ?>'s avatar + + Default avatar + + +
    +full_format($Body)?> +
    +
    + +
    +

    Post reply

    +
    +
    + + + + +
    +
    +
    + + +
    +
    + + +
    + diff --git a/sections/collages/browse.php b/sections/collages/browse.php new file mode 100644 index 00000000..cac78a5b --- /dev/null +++ b/sections/collages/browse.php @@ -0,0 +1,308 @@ +'ID', 'Name'=>'c.Name', 'Torrents'=>'NumTorrents'); +$WayTable = array('Ascending'=>'ASC', 'Descending'=>'DESC'); + +// Are we searching in bodies, or just names? +if(!empty($_GET['type'])) { + $Type = $_GET['type']; + if(!in_array($Type, array('c.name', 'description'))) { + $Type = 'c.name'; + } +} else { + $Type = 'c.name'; +} + +if(!empty($_GET['search'])) { + // What are we looking for? Let's make sure it isn't dangerous. + $Search = strtr(db_string(trim($_GET['search'])),$SpecialChars); + // Break search string down into individual words + $Words = explode(' ', $Search); +} + +if(!empty($_GET['tags'])) { + $Tags = explode(',',db_string(trim($_GET['tags']))); + foreach($Tags as $ID=>$Tag) { + $Tags[$ID] = sanitize_tag($Tag); + } +} + +if(!empty($_GET['cats'])) { + $Categories = $_GET['cats']; + foreach($Categories as $Cat=>$Accept) { + if(empty($CollageCats[$Cat]) || !$Accept) { unset($Categories[$Cat]); } + } + $Categories = array_keys($Categories); +} else { + $Categories = array(1,2,3,4,5,6); +} + +// Ordering +if(!empty($_GET['order']) && !empty($OrderTable[$_GET['order']])) { + $Order = $OrderTable[$_GET['order']]; +} else { + $Order = 'ID'; +} + +if(!empty($_GET['way']) && !empty($WayTable[$_GET['way']])) { + $Way = $WayTable[$_GET['way']]; +} else { + $Way = 'DESC'; +} + +$BookmarkView = !empty($_GET['bookmarks']); + +if ($BookmarkView) { + $BookmarkJoin = 'INNER JOIN bookmarks_collages AS bc ON c.ID = bc.CollageID'; +} else { + $BookmarkJoin = ''; +} + +$BaseSQL = $SQL = "SELECT SQL_CALC_FOUND_ROWS + c.ID, + c.Name, + c.NumTorrents, + c.TagList, + c.CategoryID, + c.UserID, + um.Username + FROM collages AS c + $BookmarkJoin + LEFT JOIN users_main AS um ON um.ID=c.UserID + WHERE Deleted = '0'"; + +if ($BookmarkView) { + $SQL .= " AND bc.UserID = '" . $LoggedUser['ID'] . "'"; +} + + + +if(!empty($Search)) { + $SQL .= " AND $Type LIKE '%"; + $SQL .= implode("%' AND $Type LIKE '%", $Words); + $SQL .= "%'"; +} + +if(!empty($Tags)) { + $SQL.= " AND TagList LIKE '%"; + $SQL .= implode("%' AND TagList LIKE '%", $Tags); + $SQL .= "%'"; +} + +if(!empty($_GET['userid'])) { + $UserID = $_GET['userid']; + if(!is_number($UserID)) { + error(404); + } + $User = user_info($UserID); + $Perms = get_permissions($User['PermissionID']); + $UserClass = $Perms['Class']; + + $UserLink = ''.$User['Username'].''; + if(!empty($_GET['contrib'])) { + if (!check_paranoia('collagecontribs', $User['Paranoia'], $UserClass, $UserID)) { error(403); } + $DB->query("SELECT DISTINCT CollageID FROM collages_torrents WHERE UserID = $UserID"); + $CollageIDs = $DB->collect('CollageID'); + if(empty($CollageIDs)) { + $SQL .= " AND 0"; + } else { + $SQL .= " AND c.ID IN(".db_string(implode(',', $CollageIDs)).")"; + } + } else { + if (!check_paranoia('collages', $User['Paranoia'], $UserClass, $UserID)) { error(403); } + $SQL .= " AND UserID='".$_GET['userid']."'"; + } + $Categories[] = 0; +} + +if(!empty($Categories)) { + $SQL.=" AND CategoryID IN(".db_string(implode(',',$Categories)).")"; +} + +if ($_GET['action'] == 'mine') { + $SQL = $BaseSQL; + $SQL .= " AND c.UserID='".$LoggedUser['ID']."' AND c.CategoryID=0"; +} + +$SQL.=" ORDER BY $Order $Way LIMIT $Limit "; +$DB->query($SQL); +$Collages = $DB->to_array(); +$DB->query("SELECT FOUND_ROWS()"); +list($NumResults) = $DB->next_record(); + +show_header(($BookmarkView)?'Your bookmarked collages':'Browse collages'); +?> +
    + +

    Your bookmarked collages

    + +

    Browse collages

    + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    Search for: + +
    Tags: + +
    Categories: +$Cat) { ?> + > + + +
    Search in: + /> Names + /> Descriptions + Order by: + + +
    + +
    +
    +
    + + + +
    + +

    You have not bookmarked any collages.

    + +

    Your search did not match anything.

    +

    Make sure all names are spelled correctly, or try making your search less specific.

    + +
    +
    + + + + + + + + +'.$Tag.''; + } + $Tags = implode(', ', $Tags); + + //Print results +?> + + + + + + + +
    CategoryCollageTorrentsAuthor
    + + + + + + [Remove bookmark] + + +
    + +
    +
    + + + diff --git a/sections/collages/collage.php b/sections/collages/collage.php new file mode 100644 index 00000000..e4898e03 --- /dev/null +++ b/sections/collages/collage.php @@ -0,0 +1,648 @@ +get_value('users_tokens_'.$UserID); +if (empty($TokenTorrents)) { + $DB->query("SELECT TorrentID FROM users_freeleeches WHERE UserID=$UserID AND Expired=FALSE"); + $TokenTorrents = $DB->collect('TorrentID'); + $Cache->cache_value('users_tokens_'.$UserID, $TokenTorrents); +} + +$Data = $Cache->get_value('collage_'.$CollageID); + +if($Data) { + $Data = unserialize($Data); + list($K, list($Name, $Description, $CollageDataList, $TorrentList, $CommentList, $Deleted, $CollageCategoryID, $CreatorID)) = each($Data); +} else { + $DB->query("SELECT Name, Description, UserID, Deleted, CategoryID, Locked, MaxGroups, MaxGroupsPerUser FROM collages WHERE ID='$CollageID'"); + if($DB->record_count() > 0) { + list($Name, $Description, $CreatorID, $Deleted, $CollageCategoryID, $Locked, $MaxGroups, $MaxGroupsPerUser) = $DB->next_record(); + $TorrentList=''; + $CollageList=''; + } else { + $Deleted = '1'; + } +} + +if($Deleted == '1') { + header('Location: log.php?search=Collage+'.$CollageID); + die(); +} + +if($CollageCategoryID == 0 && !check_perms('site_collages_delete')) { + if(!check_perms('site_collages_personal') || $CreatorID!=$LoggedUser['ID']) { + $Locked = true; + } +} + +//Handle subscriptions +if(($CollageSubscriptions = $Cache->get_value('collage_subs_user_'.$LoggedUser['ID'])) === FALSE) { + $DB->query("SELECT CollageID FROM users_collage_subs WHERE UserID = '$LoggedUser[ID]'"); + $CollageSubscriptions = $DB->collect(0); + $Cache->cache_value('collage_subs_user_'.$LoggedUser['ID'],$CollageSubscriptions,0); +} + +if(empty($CollageSubscriptions)) { + $CollageSubscriptions = array(); +} + +if(in_array($CollageID, $CollageSubscriptions)) { + $Cache->delete_value('collage_subs_user_new_'.$LoggedUser['ID']); +} +$DB->query("UPDATE users_collage_subs SET LastVisit=NOW() WHERE UserID = ".$LoggedUser['ID']." AND CollageID=$CollageID"); + + +// Build the data for the collage and the torrent list +if(!is_array($TorrentList)) { + $DB->query("SELECT ct.GroupID, + tg.WikiImage, + tg.CategoryID, + um.ID, + um.Username + FROM collages_torrents AS ct + JOIN torrents_group AS tg ON tg.ID=ct.GroupID + LEFT JOIN users_main AS um ON um.ID=ct.UserID + WHERE ct.CollageID='$CollageID' + ORDER BY ct.Sort"); + + $GroupIDs = $DB->collect('GroupID'); + $CollageDataList=$DB->to_array('GroupID', MYSQLI_ASSOC); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } +} + +// Loop through the result set, building up $Collage and $TorrentTable +// Then we print them. +$Collage = array(); +$TorrentTable = ''; + +$NumGroups = 0; +$NumGroupsByUser = 0; +$Artists = array(); +$Tags = array(); +$Users = array(); +$Number = 0; + +foreach ($TorrentList as $GroupID=>$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists, $ExtendedArtists) = array_values($Group); + list($GroupID2, $Image, $GroupCategoryID, $UserID, $Username) = array_values($CollageDataList[$GroupID]); + + // Handle stats and stuff + $Number++; + $NumGroups++; + if($UserID == $LoggedUser['ID']) { + $NumGroupsByUser++; + } + + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) { + $CountArtists = array_merge((array)$ExtendedArtists[1], (array)$ExtendedArtists[4], (array)$ExtendedArtists[5], (array)$ExtendedArtists[6]); + } else{ + $CountArtists = $GroupArtists; + } + + if($CountArtists) { + foreach($CountArtists as $Artist) { + if(!isset($Artists[$Artist['id']])) { + $Artists[$Artist['id']] = array('name'=>$Artist['name'], 'count'=>1); + } else { + $Artists[$Artist['id']]['count']++; + } + } + } + + if($Username) { + if(!isset($Users[$UserID])) { + $Users[$UserID] = array('name'=>$Username, 'count'=>1); + } else { + $Users[$UserID]['count']++; + } + } + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + $TorrentTags[]=''.$Tag.''; + } + $PrimaryTag = $TagList[0]; + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags='
    '.$TorrentTags.'
    '; + + $DisplayName = $Number.' - '; + + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5])|| !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName .= display_artists($ExtendedArtists); + } elseif(count($GroupArtists)>0) { + $DisplayName .= display_artists(array('1'=>$GroupArtists)); + } + + $DisplayName .= ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + // Start an output buffer, so we can store this output in $TorrentTable + ob_start(); + + if(count($Torrents)>1 || $GroupCategoryID==1) { + // Grouped torrents + $ShowGroups = !(!empty($LoggedUser['TorrentGrouping']) && $LoggedUser['TorrentGrouping'] == 1); +?> + + +
    + +
    + + +
    + + + + + + + $Torrent) { + + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if (in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent'])) { + $Torrent['PersonalFL'] = 1; + } + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) { + $EditionID++; + if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) { + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + +?> + + + + + + + + + + + + [ DL + 0) && ($Torrent['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1')) { ?> + | FL + + | RP ] + +   »  + + + + > + + +'.$GroupName.''; + + if(!empty($Torrent['FreeTorrent'])) { + $DisplayName .=' Freeleech!'; + } elseif(in_array($TorrentID, $TokenTorrents)) { + $DisplayName .= $AddExtra.'Personal Freeleech!'; + } +?> + + + +
    +
    + + + + [ DL + 0) && ($Torrent['Size'] < 1073741824) + && !in_array($TorrentID, $TokenTorrents) && empty($Torrent['FreeTorrent']) && ($LoggedUser['CanLeech'] == '1')) { ?> + | FL + + | RP] + + + + + + + > + + +0) { + $DisplayName .= display_artists(array('1'=>$GroupArtists), false); + } + $DisplayName .= $GroupName; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} +?> +
  17. + + + <?=$DisplayName?> + +
    + +
    +
  18. +0 && $NumGroups>=$MaxGroups) || ($MaxGroupsPerUser>0 && $NumGroupsByUser>=$MaxGroupsPerUser)) { + $Locked = true; +} + +// Silly hack for people who are on the old setting +$CollageCovers = isset($LoggedUser['CollageCovers'])?$LoggedUser['CollageCovers']:25*(abs($LoggedUser['HideCollage'] - 1)); +$CollagePages = array(); + +// Pad it out +if ($NumGroups > $CollageCovers) { + for ($i = $NumGroups + 1; $i <= ceil($NumGroups/$CollageCovers)*$CollageCovers; $i++) { + $Collage[] = '
  19. '; + } +} + + +for ($i=0; $i < $NumGroups/$CollageCovers; $i++) { + $Groups = array_slice($Collage, $i*$CollageCovers, $CollageCovers); + $CollagePage = ''; + foreach ($Groups as $Group) { + $CollagePage .= $Group; + } + $CollagePages[] = $CollagePage; +} + +show_header($Name,'browse,collage,bbcode'); +?> +
    +

    + + +
    + +
    +
    Cover Art
    +
      + +
    +
    + $CollageCovers) { ?> + + + + + + + + + + + + + + +
    TorrentsSizeSnatchesSeedersLeechers
    +
    +
    +cache_value('collage_'.$CollageID, serialize(array(array($Name, $Description, $CollageDataList, $TorrentList, $CommentList, $Deleted, $CollageCategoryID, $CreatorID, $Locked, $MaxGroups, $MaxGroupsPerUser))), 3600); +?> diff --git a/sections/collages/delete.php b/sections/collages/delete.php new file mode 100644 index 00000000..fd1dfc9e --- /dev/null +++ b/sections/collages/delete.php @@ -0,0 +1,36 @@ +query("SELECT Name, UserID FROM collages WHERE ID='$CollageID'"); +list($Name, $UserID) = $DB->next_record(); + +if(!check_perms('site_collages_delete') && $UserID != $LoggedUser['ID']) { + error(403); +} + +show_header('Delete collage'); +?> +
    +
    +
    + Delete collage +
    +
    +
    + + + + Reason: + + +
    +
    +
    +
    + diff --git a/sections/collages/delete_comment.php b/sections/collages/delete_comment.php new file mode 100644 index 00000000..cd3e7218 --- /dev/null +++ b/sections/collages/delete_comment.php @@ -0,0 +1,25 @@ +query("SELECT CollageID FROM collages_comments WHERE ID='$PostID'"); +list($CollageID) = $DB->next_record(); + +$DB->query("DELETE FROM collages_comments WHERE ID='$PostID'"); + +$Cache->delete_value('collage_'.$CollageID); +$Cache->delete('collage_'.$CollageID.'_catalogue_0'); //Because these never exceed 500 posts, and I'm really tired right now. +?> diff --git a/sections/collages/download.php b/sections/collages/download.php new file mode 100644 index 00000000..a8f2c556 --- /dev/null +++ b/sections/collages/download.php @@ -0,0 +1,196 @@ +to_array() works. What we've done, is +backwards ordering. The results returned by the +query have the best one for each GroupID last, +and while to_array traverses the results, it +overwrites the keys and leaves us with only the +desired result. This does mean however, that +the SQL has to be done in a somewhat backwards +fashion. + +Thats all you get for a disclaimer, just +remember, this page isn't for the faint of +heart. -A9 + +SQL template: +SELECT + CASE + WHEN t.Format='Ogg Vorbis' THEN 0 + WHEN t.Format='MP3' AND t.Encoding='V0 (VBR)' THEN 1 + WHEN t.Format='MP3' AND t.Encoding='V2 (VBR)' THEN 2 + ELSE 100 + END AS Rank, + t.GroupID, + t.Media, + t.Format, + t.Encoding, + IF(t.Year=0,tg.Year,t.Year), + tg.Name, + a.Name, + t.Size +FROM torrents AS t +INNER JOIN collages_torrents AS c ON t.GroupID=c.GroupID AND c.CollageID='8' +INNER JOIN torrents_group AS tg ON tg.ID=t.GroupID AND tg.CategoryID='1' +LEFT JOIN artists_group AS a ON a.ArtistID=tg.ArtistID +LEFT JOIN torrents_files AS f ON t.ID=f.TorrentID +ORDER BY t.GroupID ASC, Rank DESC, t.Seeders ASC +*/ + +if( + !isset($_REQUEST['collageid']) || + !isset($_REQUEST['preference']) || + !is_number($_REQUEST['preference']) || + !is_number($_REQUEST['collageid']) || + $_REQUEST['preference'] > 2 || + count($_REQUEST['list']) == 0 +) { error(0); } + +if(!check_perms('zip_downloader')){ error(403); } + +$Preferences = array('RemasterTitle DESC','Seeders ASC','Size ASC'); + +$CollageID = $_REQUEST['collageid']; +$Preference = $Preferences[$_REQUEST['preference']]; + +$DB->query("SELECT Name FROM collages WHERE ID='$CollageID'"); +list($CollageName) = $DB->next_record(MYSQLI_NUM,false); + +$SQL = "SELECT CASE "; + +foreach ($_REQUEST['list'] as $Priority => $Selection) { + if(!is_number($Priority)) { + continue; + } + $SQL .= "WHEN "; + switch ($Selection) { + case '00': $SQL .= "t.Format='MP3' AND t.Encoding='V0 (VBR)'"; break; + case '01': $SQL .= "t.Format='MP3' AND t.Encoding='APX (VBR)'"; break; + case '02': $SQL .= "t.Format='MP3' AND t.Encoding='256 (VBR)'"; break; + case '03': $SQL .= "t.Format='MP3' AND t.Encoding='V1 (VBR)'"; break; + case '10': $SQL .= "t.Format='MP3' AND t.Encoding='224 (VBR)'"; break; + case '11': $SQL .= "t.Format='MP3' AND t.Encoding='V2 (VBR)'"; break; + case '12': $SQL .= "t.Format='MP3' AND t.Encoding='APS (VBR)'"; break; + case '13': $SQL .= "t.Format='MP3' AND t.Encoding='192 (VBR)'"; break; + case '20': $SQL .= "t.Format='MP3' AND t.Encoding='320'"; break; + case '21': $SQL .= "t.Format='MP3' AND t.Encoding='256'"; break; + case '22': $SQL .= "t.Format='MP3' AND t.Encoding='224'"; break; + case '23': $SQL .= "t.Format='MP3' AND t.Encoding='192'"; break; + case '30': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='Vinyl'"; break; + case '31': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='DVD'"; break; + case '32': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='SACD'"; break; + case '33': $SQL .= "t.Format='FLAC' AND t.Encoding='24bit Lossless' AND t.Media='WEB'"; break; + case '34': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless' AND HasLog='1' AND LogScore='100' AND HasCue='1'"; break; + case '35': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless' AND HasLog='1' AND LogScore='100'"; break; + case '36': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless' AND HasLog='1'"; break; + case '37': $SQL .= "t.Format='FLAC' AND t.Encoding='Lossless'"; break; + case '40': $SQL .= "t.Format='DTS'"; break; + case '41': $SQL .= "t.Format='Ogg Vorbis'"; break; + case '42': $SQL .= "t.Format='AAC' AND t.Encoding='320'"; break; + case '43': $SQL .= "t.Format='AAC' AND t.Encoding='256'"; break; + case '44': $SQL .= "t.Format='AAC' AND t.Encoding='q5.5'"; break; + case '45': $SQL .= "t.Format='AAC' AND t.Encoding='q5'"; break; + case '46': $SQL .= "t.Format='AAC' AND t.Encoding='192'"; break; + default: error(0); + } + $SQL .= " THEN $Priority "; +} +$SQL .= "ELSE 100 END AS Rank, +t.GroupID, +t.ID, +t.Media, +t.Format, +t.Encoding, +IF(t.RemasterYear=0,tg.Year,t.RemasterYear), +tg.Name, +t.Size +FROM torrents AS t +INNER JOIN collages_torrents AS c ON t.GroupID=c.GroupID AND c.CollageID='$CollageID' +INNER JOIN torrents_group AS tg ON tg.ID=t.GroupID AND tg.CategoryID='1' +ORDER BY t.GroupID ASC, Rank DESC, t.$Preference"; + +$DB->query($SQL); +$Downloads = $DB->to_array('1',MYSQLI_NUM,false); +$Artists = get_artists($DB->collect('GroupID'), false); +$Skips = array(); +$TotalSize = 0; + +if(count($Downloads)) { + foreach($Downloads as $Download) { + $TorrentIDs[] = $Download[2]; + } + $DB->query("SELECT TorrentID, file FROM torrents_files WHERE TorrentID IN (".implode(',', $TorrentIDs).")"); + $Torrents = $DB->to_array('TorrentID',MYSQLI_ASSOC,false); +} + +require(SERVER_ROOT.'/classes/class_torrent.php'); +require(SERVER_ROOT.'/classes/class_zip.php'); +$Zip = new ZIP(file_string($CollageName)); +foreach($Downloads as $Download) { + list($Rank, $GroupID, $TorrentID, $Media, $Format, $Encoding, $Year, $Album, $Size) = $Download; + $Artist = display_artists($Artists[$GroupID],false,true,false); + if ($Rank == 100) { + $Skips[] = $Artist.$Album.' '.$Year; + continue; + } + $TotalSize += $Size; + $Contents = unserialize(base64_decode($Torrents[$TorrentID]['file'])); + $Tor = new TORRENT($Contents, true); + $Tor->set_announce_url(ANNOUNCE_URL.'/'.$LoggedUser['torrent_pass'].'/announce'); + unset($Tor->Val['announce-list']); + + // We need this section for long file names :/ + $TorrentName=''; + $TorrentInfo=''; + $TorrentName = file_string($Artist.$Album); + if ($Year > 0) { $TorrentName.=' - '.file_string($Year); } + if ($Media != '') { $TorrentInfo .= file_string($Media); } + if ($Format != '') { + if ($TorrentInfo!='') { $TorrentInfo .= ' - '; } + $TorrentInfo .= file_string($Format); + } + if ($Encoding!='') { + if ($TorrentInfo != '') { $TorrentInfo.=' - '; } + $TorrentInfo .= file_string($Encoding); + } + if ($TorrentInfo != '') { $TorrentInfo = " ($TorrentInfo)"; } + if (strlen($TorrentName) + strlen($TorrentInfo) + 3 > 200) { + $TorrentName = file_string($Album).(($Year>0)?(' - '.file_string($Year)):''); + } + $FileName = $TorrentName.$TorrentInfo; + $FileName = cut_string($FileName, 192, true, false); + + $Zip->add_file($Tor->enc(), $FileName.'.torrent'); +} +$Analyzed = count($Downloads); +$Skipped = count($Skips); +$Downloaded = $Analyzed - $Skipped; +$Time = number_format(((microtime(true)-$ScriptStartTime)*1000),5).' ms'; +$Used = get_size(memory_get_usage(true)); +$Date = date('M d Y, H:i'); +$Zip->add_file('Collector Download Summary - '.SITE_NAME."\r\n\r\nUser:\t\t$LoggedUser[Username]\r\nPasskey:\t$LoggedUser[torrent_pass]\r\n\r\nTime:\t\t$Time\r\nUsed:\t\t$Used\r\nDate:\t\t$Date\r\n\r\nTorrents Analyzed:\t\t$Analyzed\r\nTorrents Filtered:\t\t$Skipped\r\nTorrents Downloaded:\t$Downloaded\r\n\r\nTotal Size of Torrents (Ratio Hit): ".get_size($TotalSize)."\r\n\r\nAlbums Unavailable within your criteria (consider making a request for your desired format):\r\n".implode("\r\n",$Skips), 'Summary.txt'); +$Settings = array(implode(':',$_REQUEST['list']),$_REQUEST['preference']); +$Zip->close_stream(); + +$Settings = array(implode(':',$_REQUEST['list']),$_REQUEST['preference']); +if(!isset($LoggedUser['Collector']) || $LoggedUser['Collector'] != $Settings) { + $DB->query("SELECT SiteOptions FROM users_info WHERE UserID='$LoggedUser[ID]'"); + list($Options) = $DB->next_record(MYSQLI_NUM,false); + $Options = unserialize($Options); + $Options['Collector'] = $Settings; + $DB->query("UPDATE users_info SET SiteOptions='".db_string(serialize($Options))."' WHERE UserID='$LoggedUser[ID]'"); + $Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']); + $Cache->insert('Collector',$Settings); + $Cache->commit_transaction(0); +} +?> diff --git a/sections/collages/edit.php b/sections/collages/edit.php new file mode 100644 index 00000000..76275316 --- /dev/null +++ b/sections/collages/edit.php @@ -0,0 +1,77 @@ +query("SELECT Name, Description, TagList, UserID, CategoryID, Locked, MaxGroups, MaxGroupsPerUser, Featured FROM collages WHERE ID='$CollageID'"); +list($Name, $Description, $TagList, $UserID, $CategoryID, $Locked, $MaxGroups, $MaxGroupsPerUser, $Featured) = $DB->next_record(); +$TagList = implode(', ', explode(' ', $TagList)); + +if($CategoryID == 0 && $UserID!=$LoggedUser['ID'] && !check_perms('site_collages_delete')) { error(403); } + +show_header('Edit collage'); +?> +
    +

    Edit collage

    +
    + + + + + + + + + + +0) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name
    Category + +
    Description + +
    Tags
    Featured />
    Lockedchecked="checked" />
    Max groups
    Max groups per user
    +
    +
    + diff --git a/sections/collages/edit_handle.php b/sections/collages/edit_handle.php new file mode 100644 index 00000000..648b4cf0 --- /dev/null +++ b/sections/collages/edit_handle.php @@ -0,0 +1,50 @@ +query("SELECT UserID, CategoryID FROM collages WHERE ID='$CollageID'"); +list($UserID, $CategoryID) = $DB->next_record(); +if($CategoryID == 0 && $UserID!=$LoggedUser['ID'] && !check_perms('site_collages_delete')) { error(403); } + +$DB->query("SELECT ID,Deleted FROM collages WHERE Name='".db_string($_POST['name'])."' AND ID!='$CollageID' LIMIT 1"); +if($DB->record_count()) { + list($ID, $Deleted) = $DB->next_record(); + if($Deleted) { + $Err = 'A collage with that name already exists but needs to be recovered, please contact the staff team!'; + } else { + $Err = "A collage with that name already exists: $ID."; + } +} + +$TagList = explode(',',$_POST['tags']); +foreach($TagList as $ID=>$Tag) { + $TagList[$ID] = sanitize_tag($Tag); +} +$TagList = implode(' ',$TagList); + +$DB->query("UPDATE collages SET Description='".db_string($_POST['description'])."', TagList='$TagList' WHERE ID='$CollageID'"); + +if (!check_perms('site_collages_delete') && ($CategoryID == 0 && $UserID == $LoggedUser['ID'] && check_perms('site_collages_renamepersonal'))) { + if(!stristr($_POST['name'], $LoggedUser['Username'])) { + error("Your personal collage's title must include your username."); + } +} + +if (isset($_POST['featured']) && $CategoryID == 0 && (($LoggedUser['ID'] == $UserID && check_perms('site_collages_personal')) || check_perms('site_collages_delete'))) { + $DB->query("UPDATE collages SET Featured=0 WHERE CategoryID=0 and UserID=$UserID"); + $DB->query("UPDATE collages SET Featured=1 WHERE ID=$CollageID"); +} + +if (check_perms('site_collages_delete') || ($CategoryID == 0 && $UserID == $LoggedUser['ID'] && check_perms('site_collages_renamepersonal'))) { + $DB->query("UPDATE collages SET Name='".db_string($_POST['name'])."' WHERE ID='$CollageID'"); +} + +if(!empty($_POST['category']) && !empty($CollageCats[$_POST['category']]) && $_POST['category']!=$CategoryID && $_POST['category']!=0) { + $DB->query("UPDATE collages SET CategoryID='".db_string($_POST['category'])."' WHERE ID='$CollageID'"); +} + +$Cache->delete_value('collage_'.$CollageID); +header('Location: collages.php?id='.$CollageID); +?> diff --git a/sections/collages/get_post.php b/sections/collages/get_post.php new file mode 100644 index 00000000..f1dfd7be --- /dev/null +++ b/sections/collages/get_post.php @@ -0,0 +1,27 @@ +query("SELECT Body FROM collages_comments WHERE ID='$PostID'"); +list($Body) = $DB->next_record(MYSQLI_NUM); + +// This gets sent to the browser, which echoes it wherever + +echo trim($Body); diff --git a/sections/collages/index.php b/sections/collages/index.php new file mode 100644 index 00000000..48f4979f --- /dev/null +++ b/sections/collages/index.php @@ -0,0 +1,93 @@ +query("SELECT COUNT(ID) FROM collages WHERE UserID='$LoggedUser[ID]' AND CategoryID='0' AND Deleted='0'"); + list($CollageCount) = $DB->next_record(); + + if($CollageCount >= $LoggedUser['Permissions']['MaxCollages']) { + list($CollageID) = $DB->next_record(); + header('Location: collage.php?id='.$CollageID); + die(); + } + $NameStr = ($CollageCount > 0)?" no. " . ($CollageCount + 1):''; + $DB->query("INSERT INTO collages (Name, Description, CategoryID, UserID) VALUES ('$LoggedUser[Username]\'s personal collage$NameStr', 'Personal collage for $LoggedUser[Username]. The first 5 albums will appear on his or her [url=http:\/\/".NONSSL_SITE_URL."\/user.php?id=$LoggedUser[ID]]profile[\/url].', '0', $LoggedUser[ID])"); + $CollageID = $DB->inserted_id(); + header('Location: collage.php?id='.$CollageID); + die(); + + default: + if(!empty($_GET['id'])) { + require(SERVER_ROOT.'/sections/collages/collage.php'); + } else { + require(SERVER_ROOT.'/sections/collages/browse.php'); + } + break; +} + +?> diff --git a/sections/collages/manage.php b/sections/collages/manage.php new file mode 100644 index 00000000..d4b6717c --- /dev/null +++ b/sections/collages/manage.php @@ -0,0 +1,90 @@ +query("SELECT Name, UserID, CategoryID FROM collages WHERE ID='$CollageID'"); +list($Name, $UserID, $CategoryID) = $DB->next_record(); +if($CategoryID == 0 && $UserID!=$LoggedUser['ID'] && !check_perms('site_collages_delete')) { error(403); } + +$DB->query("SELECT ct.GroupID, + um.ID, + um.Username, + ct.Sort + FROM collages_torrents AS ct + JOIN torrents_group AS tg ON tg.ID=ct.GroupID + LEFT JOIN users_main AS um ON um.ID=ct.UserID + WHERE ct.CollageID='$CollageID' + ORDER BY ct.Sort"); + +$GroupIDs = $DB->collect('GroupID'); + +$CollageDataList=$DB->to_array('GroupID', MYSQLI_ASSOC); +if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs); + $TorrentList = $TorrentList['matches']; +} else { + $TorrentList = array(); +} + +show_header('Manage collage '.$Name); +?> +
    +

    Manage collage

    + + + + + + + +$Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists, $ExtendedArtists) = array_values($Group); + list($GroupID2, $UserID, $Username, $Sort) = array_values($CollageDataList[$GroupID]); + + + $Number++; + + $DisplayName = $Number.' - '; + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5])|| !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName .= display_artists($ExtendedArtists); + } elseif(count($GroupArtists)>0) { + $DisplayName .= display_artists(array('1'=>$GroupArtists)); + } + $DisplayName .= ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + +?> + + + + + + + + + + + + + +
    SortTorrentUserSubmit
    + + + + + + + + +
    +
    + diff --git a/sections/collages/manage_handle.php b/sections/collages/manage_handle.php new file mode 100644 index 00000000..3eda8e76 --- /dev/null +++ b/sections/collages/manage_handle.php @@ -0,0 +1,29 @@ +query("SELECT UserID, CategoryID FROM collages WHERE ID='$CollageID'"); +list($UserID, $CategoryID) = $DB->next_record(); +if($CategoryID == 0 && $UserID!=$LoggedUser['ID'] && !check_perms('site_collages_delete')) { error(403); } + +$GroupID = $_POST['groupid']; +if(!is_number($GroupID)) { error(404); } + + +if($_POST['submit'] == 'Remove') { + $DB->query("DELETE FROM collages_torrents WHERE CollageID='$CollageID' AND GroupID='$GroupID'"); + $Rows = $DB->affected_rows(); + $DB->query("UPDATE collages SET NumTorrents=NumTorrents-$Rows WHERE ID='$CollageID'"); + $Cache->delete_value('torrents_details_'.$GroupID); + $Cache->delete_value('torrent_collages_'.$GroupID); + $Cache->delete_value('torrent_collages_personal_'.$GroupID); +} else { + $Sort = $_POST['sort']; + if(!is_number($Sort)) { error(404); } + $DB->query("UPDATE collages_torrents SET Sort='$Sort' WHERE CollageID='$CollageID' AND GroupID='$GroupID'"); +} +$Cache->delete_value('collage_'.$CollageID); +header('Location: collages.php?action=manage&collageid='.$CollageID); +?> diff --git a/sections/collages/new.php b/sections/collages/new.php new file mode 100644 index 00000000..fb25845a --- /dev/null +++ b/sections/collages/new.php @@ -0,0 +1,89 @@ + +
    + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name + + 's personal collage +
    Category + +
    +
      +
    • Theme - A collage containing releases that all relate to a certain theme (Searching for the perfect beat, for instance)
    • +
    • Genre introduction - A subjective introduction to a Genre composed by our own users
    • +
    • Discography - A collage containing all the releases of an artist, when that artist has a multitude of side projects
    • +
    • Label - A collage containing all the releases of a particular record label
    • +
    • Staff picks - A list of recommendations picked by the staff on special occasions
    • +
    • Charts - A collage containing all the releases that comprise a certain chart (Billboard Top 100, Pitchfork Top 100, What.cd Top 10 for a certain week)
    • + +
    • Personal - You can put whatever your want here. It's your personal collage.
    • + +
    +
    Description + +
    Tags (comma-separated) + +
    + Please ensure your collage will be allowed under the rules +
    +
    +
    + diff --git a/sections/collages/new_handle.php b/sections/collages/new_handle.php new file mode 100644 index 00000000..30cafad9 --- /dev/null +++ b/sections/collages/new_handle.php @@ -0,0 +1,83 @@ + 0 || check_perms('site_collages_renamepersonal')) { + $Val->SetFields('name', '1','string','The name must be between 3 and 100 characters',array('maxlength'=>100, 'minlength'=>3)); +} else { + // Get a collage name and make sure it's unique + $name = $LoggedUser['Username']."'s personal collage"; + $P['name'] = db_string($name); + $DB->query("SELECT ID FROM collages WHERE Name='".$P['name']."'"); + $i = 2; + while ($DB->record_count() != 0) { + $P['name'] = db_string($name." no. $i"); + $DB->query("SELECT ID FROM collages WHERE Name='".$P['name']."'"); + $i++; + } +} +$Val->SetFields('description', '1','string','The description must be at least 10 characters',array('maxlength'=>65535, 'minlength'=>10)); + +$Err = $Val->ValidateForm($_POST); + +if ($P['category'] == '0') { + $DB->query("SELECT COUNT(ID) FROM collages WHERE UserID='$LoggedUser[ID]' AND CategoryID='0' AND Deleted='0'"); + list($CollageCount) = $DB->next_record(); + if (($CollageCount >= $LoggedUser['Permissions']['MaxCollages']) || !check_perms('site_collages_personal')) { + $Err = 'You may not create a personal collage.'; + } elseif (check_perms('site_collages_renamepersonal') && !stristr($P['name'], $LoggedUser['Username'])) { + $Err = 'Your personal collage\'s title must include your username.'; + } +} + +if(!$Err) { + $DB->query("SELECT ID,Deleted FROM collages WHERE Name='$P[name]'"); + if($DB->record_count()) { + list($ID, $Deleted) = $DB->next_record(); + if($Deleted) { + $Err = 'That collection already exists but needs to be recovered, please contact the staff team!'; + } else { + $Err = "That collection already exists: $ID."; + } + } +} + +if(!$Err) { + if(empty($CollageCats[$P['category']])) { + $Err = 'Please select a category'; + } +} + +if($Err) { + //error($Err); + $Err = urlencode($Err); + $Name = urlencode($_POST['name']); + $Category = urlencode($_POST['category']); + $Tags = urlencode($_POST['tags']); + $Description = urlencode($_POST['description']); + header("Location: collages.php?action=new&err=$Err&name=$Name&cat=$Category&tags=$Tags&descr=$Description"); + die(); +} + +$TagList = explode(',',$_POST['tags']); +foreach($TagList as $ID=>$Tag) { + $TagList[$ID] = sanitize_tag($Tag); +} +$TagList = implode(' ',$TagList); + +$DB->query("INSERT INTO collages + (Name, Description, UserID, TagList, CategoryID) + VALUES + ('$P[name]', '$P[description]', $LoggedUser[ID], '$TagList', '$P[category]')"); + +$CollageID = $DB->inserted_id(); +$Cache->delete_value('collage_'.$CollageID); +write_log("Collage ".$CollageID." (".$P[name].") was created by ".$LoggedUser['Username']); +header('Location: collages.php?id='.$CollageID); + +?> diff --git a/sections/collages/recover.php b/sections/collages/recover.php new file mode 100644 index 00000000..8046e472 --- /dev/null +++ b/sections/collages/recover.php @@ -0,0 +1,39 @@ +query("SELECT Name FROM collages WHERE ID = ".$CollageID); + if($DB->record_count() == 0) { + error('Collage is completely deleted'); + } else { + $DB->query("UPDATE collages SET Deleted = '0' WHERE ID=$CollageID"); + $Cache->delete_value('collage_'.$CollageID); + write_log("Collage ".$CollageID." was recovered by ".$LoggedUser['Username']); + header("Location: collages.php?id=$CollageID"); + } +} +show_header("Collage recovery!"); +?> +
    +
    +
    + Recover deleted collage +
    +
    +
    + + + ID: + + +
    +
    +
    +
    +query("SELECT Name, CategoryID, UserID FROM collages WHERE ID='$CollageID'"); +list($Name, $CategoryID, $UserID) = $DB->next_record(); + +if(!check_perms('site_collages_delete') && $UserID != $LoggedUser['ID']) { + error(403); +} + +$Reason = trim($_POST['reason']); +if(!$Reason) { + error("You must enter a reason!"); +} + +$DB->query("SELECT GroupID FROM collages_torrents WHERE CollageID='$CollageID'"); +while(list($GroupID) = $DB->next_record()) { + $Cache->delete_value('torrents_details_'.$GroupID); + $Cache->delete_value('torrent_collages_'.$GroupID); + $Cache->delete_value('torrent_collages_personal_'.$GroupID); +} + +//Personal collages have CategoryID 0 +if ($CategoryID == 0) { + $DB->query("DELETE FROM collages WHERE ID='$CollageID'"); + $DB->query("DELETE FROM collages_torrents WHERE CollageID='$CollageID'"); + $DB->query("DELETE FROM collages_comments WHERE CollageID='$CollageID'"); +} else { + $DB->query("UPDATE collages SET Deleted = '1' WHERE ID='$CollageID'"); +} + +write_log("Collage ".$CollageID." (".$Name.") was deleted by ".$LoggedUser['Username'].": ".$Reason); + +$Cache->delete_value('collage_'.$CollageID); +header('Location: collages.php'); diff --git a/sections/collages/takeedit_comment.php b/sections/collages/takeedit_comment.php new file mode 100644 index 00000000..b0a620c7 --- /dev/null +++ b/sections/collages/takeedit_comment.php @@ -0,0 +1,49 @@ +query("SELECT cc.Body, cc.UserID, cc.CollageID, (SELECT COUNT(ID) FROM collages_comments WHERE ID <= ".$PostID." AND collages_comments.CollageID = cc.CollageID) FROM collages_comments AS cc WHERE cc.ID='$PostID'"); +list($OldBody, $AuthorID, $CollageID, $PostNum) = $DB->next_record(); + +// Make sure they aren't trying to edit posts they shouldn't +// We use die() here instead of error() because whatever we spit out is displayed to the user in the box where his forum post is +if($UserID!=$AuthorID && !check_perms('site_moderate_forums')) { + die('Permission denied'); +} +if($DB->record_count()==0) { + die('Post not found!'); +} + +// Perform the update +$DB->query("UPDATE collages_comments SET + Body = '$Body' + WHERE ID='$PostID'"); + +$Cache->delete_value('collage_'.$CollageID); + + +$PageNum = ceil($PostNum / TORRENT_COMMENTS_PER_PAGE); +$CatalogueID = floor((POSTS_PER_PAGE*$PageNum-POSTS_PER_PAGE)/THREAD_CATALOGUE); +$Cache->delete_value('collage_'.$CollageID.'_catalogue_'.$CatalogueID); + +$DB->query("INSERT INTO comments_edits (Page, PostID, EditUser, EditTime, Body) + VALUES ('collages', ".$PostID.", ".$UserID.", '".sqltime()."', '".db_string($OldBody)."')"); + +// This gets sent to the browser, which echoes it in place of the old body +echo $Text->full_format($_POST['body']); + +?> diff --git a/sections/comments/index.php b/sections/comments/index.php new file mode 100644 index 00000000..b789323e --- /dev/null +++ b/sections/comments/index.php @@ -0,0 +1,181 @@ + t.Time"; + $Title = 'Comments left on your torrents'; + $Header = 'Comments left on your uploads'; + if($Self) $OtherLink = 'Display comments you\'ve made'; +} +else { + $Conditions = "WHERE tc.AuthorID = $UserID"; + $Title = 'Comments made by '.($Self?'you':$Username); + $Header = 'Torrent comments left by '.($Self?'you':format_username($UserID, $Username)).''; + if($Self) $OtherLink = 'Display comments left on your uploads'; +} + +$Comments = $DB->query("SELECT + SQL_CALC_FOUND_ROWS + m.ID, + m.Username, + m.PermissionID, + m.Enabled, + + i.Avatar, + i.Donor, + i.Warned, + + t.ID, + t.GroupID, + + tg.Name, + + tc.ID, + tc.Body, + tc.AddedTime, + tc.EditedTime, + + em.ID as EditorID, + em.Username as EditorUsername + + FROM torrents as t + JOIN torrents_comments as tc ON tc.GroupID = t.GroupID + JOIN users_main as m ON tc.AuthorID = m.ID + JOIN users_info as i ON i.UserID = m.ID + JOIN torrents_group as tg ON t.GroupID = tg.ID + LEFT JOIN users_main as em ON em.ID = tc.EditedUserID + + $Conditions + + GROUP BY tc.ID + + ORDER BY tc.AddedTime DESC + + LIMIT $Limit; +"); + +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); +$Pages=get_pages($Page,$Results,$PerPage, 11); + +$DB->set_query_id($Comments); +$GroupIDs = $DB->collect('GroupID'); + +$Artists = get_artists($GroupIDs); + +$DB->set_query_id($Comments); +show_header($Title,'bbcode'); + +?>
    +

    + +

    + + +next_record()) { + ?> + ' id="post"> + + + + + + + + + +
    + # + by + on + +
    + + <?=$Username ?>'s avatar + + Default avatar + + + full_format($Body) ?> + +

    + Last edited by + + + +
    + + +
    + diff --git a/sections/donate/cancel.php b/sections/donate/cancel.php new file mode 100644 index 00000000..67c471fd --- /dev/null +++ b/sections/donate/cancel.php @@ -0,0 +1,11 @@ + +
    +

    Donation Canceled

    +
    +

    It's the thought that counts. Please reconsider donating in the future.

    +
    +
    + \ No newline at end of file diff --git a/sections/donate/complete.php b/sections/donate/complete.php new file mode 100644 index 00000000..79e49eff --- /dev/null +++ b/sections/donate/complete.php @@ -0,0 +1,11 @@ + +
    +

    Donation Complete

    +
    +

    Thank you for your donation! If this is your first time donating you will now have recieved 2 invitations and a Donor.

    +
    +
    + diff --git a/sections/donate/donate.php b/sections/donate/donate.php new file mode 100644 index 00000000..767e79a9 --- /dev/null +++ b/sections/donate/donate.php @@ -0,0 +1,103 @@ +get_value('stats_user_count')){ + $DB->query("SELECT COUNT(ID) FROM users_main WHERE Enabled='1'"); + list($UserCount) = $DB->next_record(); + $Cache->cache_value('stats_user_count', $UserCount, 0); //inf cache +} + +$DonorPerms = get_permissions(DONOR); + +if ($_GET['miner']) { $LoggedUser['BitcoinMiner'] = 1; $_GET['showminer'] = 1; } +show_header('Donate'); + + +?> + +
    + + diff --git a/sections/donate/donate_gpal.php b/sections/donate/donate_gpal.php new file mode 100644 index 00000000..d217661f --- /dev/null +++ b/sections/donate/donate_gpal.php @@ -0,0 +1,104 @@ +get_value('stats_user_count')){ + $DB->query("SELECT COUNT(ID) FROM users_main WHERE Enabled='1'"); + list($UserCount) = $DB->next_record(); + $Cache->cache_value('stats_user_count', $UserCount, 0); //inf cache +} + +$DonorPerms = get_permissions(DONOR); + +show_header('Donate'); + + +?> + +
    + +

    Test IPN

    +
    +
    + + + + + + + + + + + + +
    +
    + +

    Donate

    +
    +

    We accept donations to cover the costs associated with running the site and tracker. These costs come from the rental and purchase of the hardware the site runs on (Servers, Components, etc.), in addition to operating expenses (Bandwidth, Power, etc.).

    +

    Because we do not have any advertisements or sponsorships and this service is provided free of charge, we are entirely reliant upon user donations. If you are financially able, please consider making a donation to help us pay the bills!

    +

    We currently only accept one payment method; PayPal. Because of the fees they charge, there is a minimum donation amount of (Please note, this is only a minimum amount and we greatly appreciate any extra you can afford.).

    +

    You don't have to be a PayPal member to make a donation, you can simply donate with your credit/debit card. If you do not have a credit/debit card, you should be able to donate from your bank account, but you will need to make an account with them to do this.

    +
    + + + + + + + + + + + + + + + +
    +
    + +?> +

    What you will receive for a 5€ or 2 BTC minimum donation

    +
    +
      + +
    • Even more love! (You will not get multiple hearts.)
    • +
    • A warmer fuzzier feeling than before!
    • + +
    • Our eternal love, as represented by the Donor you get next to your name.
    • += USER_LIMIT && !check_perms('site_can_invite_always') && !isset($DonorPerms['site_can_invite_always'])) { +?> +
    • Note: Because the user limit has been reached, you will be unable to use the invites recieved until a later date.
    • + +
    • A warm fuzzy feeling.
    • + + +
    +

    Please be aware that by making a donation you aren't purchasing donor status or invites. You are helping us pay the bills and cover the costs of running the site. We are doing our best to give our love back to donors but sometimes it might take more than 48 hours. Feel free to contact us by sending us a Staff PM regarding any matter. We will answer as quickly as possible.

    +
    +

    What you will not receive

    +
    +
      + +
    • 2 more invitations, these were one time only.
    • + +
    • Immunity from the rules.
    • +
    • Additional upload credit.
    • +
    +
    +
    + +

    Test IPN

    +
    +
    + + + + + + + + + + + + +
    +
    + +

    Donate

    +
    +

    We accept donations to cover the costs associated with running the site and tracker. These costs come from the rental and purchase of the hardware the site runs on (Servers, Components, etc.), in addition to operating expenses (Bandwidth, Power, etc.).

    +

    Because we do not have any advertisements or sponsorships and this service is provided free of charge, we are entirely reliant upon user donations. If you are financially able, please consider making a donation to help us pay the bills!

    +

    We currently only accept one payment method; PayPal. Because of the fees they charge, there is a minimum donation amount of (Please note, this is only a minimum amount and we greatly appreciate any extra you can afford.).

    +

    You don't have to be a PayPal member to make a donation, you can simply donate with your credit/debit card. If you do not have a credit/debit card, you should be able to donate from your bank account, but you will need to make an account with them to do this.

    +
    + + + + + + + + + + + + + + + +
    +
    + +?> +

    What you will receive for a 5€ minimum donation

    +
    +
      + +
    • Even more love! (You will not get multiple hearts.)
    • +
    • A warmer fuzzier feeling than before!
    • + +
    • Our eternal love, as represented by the Donor you get next to your name.
    • +
    • 2 invitations, to invite 2 good friends to use this tracker.
    • += USER_LIMIT && !check_perms('site_can_invite_always') && !isset($DonorPerms['site_can_invite_always'])) { +?> +
    • Note: Because the user limit has been reached, you will be unable to use the invites recieved until a later date.
    • + +
    • Immunity to inactivity pruning.
    • +
    • Access to an ever growing list of exclusive features, including the ability to submit requests and personal collages.
    • +
    • A warm fuzzy feeling.
    • + + +
    +
    +

    What you will not receive

    +
    +
      + +
    • 2 more invitations, these were one time only.
    • + +
    • Immunity from the rules.
    • +
    • Additional upload credit.
    • +
    +
    +
    + + diff --git a/sections/donate/index.php b/sections/donate/index.php new file mode 100644 index 00000000..bb7c5cb5 --- /dev/null +++ b/sections/donate/index.php @@ -0,0 +1,21 @@ + diff --git a/sections/donate/ipn.php b/sections/donate/ipn.php new file mode 100644 index 00000000..4778ee3b --- /dev/null +++ b/sections/donate/ipn.php @@ -0,0 +1,110 @@ + $Value) { + $Value = urlencode(stripslashes($Value)); + $Request .= "&$Key=$Value"; +} + +// Headers +$Headers = "POST /cgi-bin/webscr HTTP/1.1\r\n"; +$Headers .= "Host: www.paypal.com\r\n"; +$Headers .= "Content-Type: application/x-www-form-urlencoded\r\n"; +$Headers .= "Content-Length: ".strlen($Request)."\r\n"; +$Headers .= "Connection: close\r\n\r\n"; + +// Socket +$Socket = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30); + +// Send and process reply +fwrite ($Socket, $Headers.$Request); +$Result = ''; +while (!feof($Socket)) { + $Result .= fgets ($Socket, 1024); +} + +if (strpos($Result,'VERIFIED') !== false || check_perms('site_debug')) { + if ($_POST['mc_gross'] >= PAYPAL_MINIMUM) { + if ($_POST['mc_currency'] == PAYPAL_CURRENCY) { + if ($_POST['business'] == PAYPAL_ADDRESS) { + if (($_POST['payment_status'] == "Completed") || ($_POST['payment_status'] == "Pending")) { + $DB->query('SELECT Donor FROM users_info WHERE UserID=\''.$_POST['custom'].'\''); + list($Donor) = $DB->next_record(); + if($Donor == 0){ + //First time donor + $DB->query('UPDATE users_main SET Invites = Invites + \''.DONOR_INVITES.'\' WHERE ID=\''.$_POST['custom'].'\''); + $DB->query('UPDATE users_info SET Donor = \'1\' WHERE UserID=\''.$_POST['custom'].'\''); + $DB->query('SELECT Invites FROM users_main WHERE ID=\''.$_POST['custom'].'\''); + list($Invites) = $DB->next_record(); + $Cache->begin_transaction('user_info_'.$_POST['custom']); + $Cache->update_row(false, array('Donor' => 1)); + $Cache->commit_transaction(0); + $Cache->begin_transaction('user_info_heavy_'.$_POST['custom']); + $Cache->update_row(false, array('Invites' => $Invites)); + $Cache->commit_transaction(0); + send_pm($_POST['custom'],0,db_string('Thank you for your donation'),db_string('Your donation from '.$_POST['payer_email'].' of '.$_POST['mc_gross'].' '.PAYPAL_CURRENCY.' has been successfully processed. Because this is your first time donating, you have now been awarded Donor status as represented by the <3 found on your profile and next to your username where it appears. This has entitled you to a additional site features which you can now explore, and has granted you '.DONOR_INVITES.' invitations to share with others. Thank you for supporting '.SITE_NAME.'.'),''); + } else { + //Repeat donor + send_pm($_POST['custom'],0,db_string('Thank you for your donation'),db_string('Your donation from '.$_POST['payer_email'].' of '.$_POST['mc_gross'].' '.PAYPAL_CURRENCY.' has been successfully processed. Your continued support is highly appreciated and helps to make this place possible.'),''); + } + + + } + } + } + } else { + if ($_POST['mc_gross'] > 0) { + //Donation less than minimum + send_pm($_POST['custom'],0,db_string('Thank you for your donation'),db_string('Your donation from '.$_POST['payer_email'].' of '.$_POST['mc_gross'].' '.PAYPAL_CURRENCY.' has been successfully processed. Unfortunately however this donation was less than the specified minimum donation of '.PAYPAL_MINIMUM.' '.PAYPAL_CURRENCY.' and while we are grateful, no special privileges have been awarded to you.'),''); + } else { + //Failed pending donation + $Message = "User http://".NONSSL_SITE_URL."/user.php?id=".$_POST['custom']." had donation of ".$TotalDonated." ".PAYPAL_CURRENCY." at ".$DonationTime." UTC from ".$_POST['payer_email']." returned."; + $DB->query('SELECT SUM(Amount), MIN(Time) FROM donations WHERE UserID=\''.$_POST['custom'].'\';'); + list($TotalDonated,$DonationTime) = $DB->next_record(); + if ($TotalDonated+$_POST['mc_gross'] == 0) { + $DB->query("SELECT Invites FROM users_main WHERE ID='".$_POST['custom']."'"); + list($Invites) = $DB->next_record(); + if(($Invites - DONOR_INVITES) >= 0) { + $NewInvites = $Invites - DONOR_INVITES; + } else { + $NewInvites = 0; + $Message .= " They had already used at least one of their donation gained invites."; + } + $DB->query("UPDATE users_main SET Invites = ".$NewInvites." WHERE ID='".$_POST['custom']."'"); + $DB->query('UPDATE users_info SET Donor = \'0\' WHERE UserID=\''.$_POST['custom'].'\''); + $Cache->begin_transaction('user_info_'.$_POST['custom']); + $Cache->update_row(false, array('Donor' => 0)); + $Cache->commit_transaction(0); + $Cache->begin_transaction('user_info_heavy_'.$_POST['custom']); + $Cache->update_row(false, array('Invites' => $Invites)); + $Cache->commit_transaction(0); + send_pm($_POST['custom'],0,db_string('Notice of donation failure'),db_string('PapPal has just notified us that the donation you sent from '.$_POST['payer_email'].' of '.$TotalDonated.' '.PAYPAL_CURRENCY.' at '.$DonationTime.' UTC has been revoked. Because of this your special privileges have been revoked, and your invites removed.'),''); + + + send_irc("PRIVMSG ".BOT_REPORT_CHAN." :".$Message); + } + } + } + $DB->query("UPDATE users_info + SET + AdminComment=CONCAT('".sqltime()." - User donated ".db_string($_POST['mc_gross'])." ".db_string(PAYPAL_CURRENCY)." from ".db_string($_POST['payer_email']).".\n',AdminComment) + WHERE UserID='".$_POST['custom']."'"); + $DB->query("INSERT INTO donations + (UserID, Amount, Email, Time) VALUES + ('".$_POST['custom']."', '".db_string($_POST['mc_gross'])."', '".db_string($_POST['payer_email'])."', '".sqltime()."')"); +} else { + $DB->query("INSERT INTO ip_bans + (FromIP, ToIP, Reason) VALUES + ('".ip2unsigned($_SERVER['REMOTE_ADDR'])."','".ip2long($_SERVER['REMOTE_ADDR'])."', 'Attempted to exploit donation system.')"); +} +fclose ($Socket); +if (check_perms('site_debug')) { + include(SERVER_ROOT.'/sections/donate/donate.php'); +} +$Cache->cache_value('debug_donate',array($Result,$_POST),0); +?> diff --git a/sections/error/403.php b/sections/error/403.php new file mode 100644 index 00000000..83a622e9 --- /dev/null +++ b/sections/error/403.php @@ -0,0 +1,5 @@ +

    Error: 403

    Forbidden. +Error: 404 Not Found. +Error: 413 Request is too large. +Error: 504 Gateway timeout. + +
    +

    +
    +

    +
    +
    +open_feed(); + $Feed->channel('Blocked', 'RSS feed.'); + $Feed->close_feed(); + die(); +} + +$User = (int)$_GET['user']; + +if(!$Enabled = $Cache->get_value('enabled_'.$User)){ + require(SERVER_ROOT.'/classes/class_mysql.php'); + $DB=NEW DB_MYSQL; //Load the database wrapper + $DB->query("SELECT Enabled FROM users_main WHERE ID='$User'"); + list($Enabled) = $DB->next_record(); + $Cache->cache_value('enabled_'.$User, $Enabled, 0); +} + +if (md5($User.RSS_HASH.$_GET['passkey']) != $_GET['auth'] || $Enabled != 1) { + $Feed->open_feed(); + $Feed->channel('Blocked', 'RSS feed.'); + + + $Feed->close_feed(); + die(); +} + +$Feed->open_feed(); +switch($_GET['feed']) { + case 'feed_news': + include(SERVER_ROOT.'/classes/class_text.php'); + $Text = new TEXT; + $Feed->channel('News', 'RSS feed for site news.'); + if (!$News = $Cache->get_value('news')) { + require(SERVER_ROOT.'/classes/class_mysql.php'); //Require the database wrapper + $DB=NEW DB_MYSQL; //Load the database wrapper + $DB->query("SELECT + ID, + Title, + Body, + Time + FROM news + ORDER BY Time DESC + LIMIT 10"); + $News = $DB->to_array(false,MYSQLI_NUM,false); + $Cache->cache_value('news',$News,1209600); + } + $Count = 0; + foreach ($News as $NewsItem) { + list($NewsID,$Title,$Body,$NewsTime) = $NewsItem; + if (strtotime($NewsTime) >= time()) { + continue; + } + echo $Feed->item($Title, $Text->strip_bbcode($Body), 'index.php#news'.$NewsID, SITE_NAME.' Staff','','',$NewsTime); + if (++$Count > 4) { + break; + } + } + break; + case 'feed_blog': + include(SERVER_ROOT.'/classes/class_text.php'); + $Text = new TEXT; + $Feed->channel('Blog', 'RSS feed for site blog.'); + if (!$Blog = $Cache->get_value('blog')) { + require(SERVER_ROOT.'/classes/class_mysql.php'); //Require the database wrapper + $DB=NEW DB_MYSQL; //Load the database wrapper + $DB->query("SELECT + b.ID, + um.Username, + b.Title, + b.Body, + b.Time, + b.ThreadID + FROM blog AS b LEFT JOIN users_main AS um ON b.UserID=um.ID + ORDER BY Time DESC + LIMIT 20"); + $Blog = $DB->to_array(); + $Cache->cache_value('Blog',$Blog,1209600); + } + foreach ($Blog as $BlogItem) { + list($BlogID, $Author, $Title, $Body, $BlogTime, $ThreadID) = $BlogItem; + echo $Feed->item($Title, $Text->strip_bbcode($Body), 'forums.php?action=viewthread&threadid='.$ThreadID, SITE_NAME.' Staff','','',$BlogTime); + } + break; + case 'torrents_all': + $Feed->channel('All Torrents', 'RSS feed for all new torrent uploads.'); + $Feed->retrieve('torrents_all',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_music': + $Feed->channel('Music Torrents', 'RSS feed for all new music torrents.'); + $Feed->retrieve('torrents_music',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_apps': + $Feed->channel('Application Torrents', 'RSS feed for all new application torrents.'); + $Feed->retrieve('torrents_apps',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_ebooks': + $Feed->channel('E-Book Torrents', 'RSS feed for all new e-book torrents.'); + $Feed->retrieve('torrents_ebooks',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_abooks': + $Feed->channel('Audiobook Torrents', 'RSS feed for all new audiobook torrents.'); + $Feed->retrieve('torrents_abooks',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_evids': + $Feed->channel('E-Learning Video Torrents', 'RSS feed for all new e-learning video torrents.'); + $Feed->retrieve('torrents_evids',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_comedy': + $Feed->channel('Comedy Torrents', 'RSS feed for all new comedy torrents.'); + $Feed->retrieve('torrents_comedy',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_comics': + $Feed->channel('Comic Torrents', 'RSS feed for all new comic torrents.'); + $Feed->retrieve('torrents_comics',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_mp3': + $Feed->channel('MP3 Torrents', 'RSS feed for all new mp3 torrents.'); + $Feed->retrieve('torrents_mp3',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_flac': + $Feed->channel('FLAC Torrents', 'RSS feed for all new FLAC torrents.'); + $Feed->retrieve('torrents_flac',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_vinyl': + $Feed->channel('Vinyl Sourced Torrents', 'RSS feed for all new vinyl sourced torrents.'); + $Feed->retrieve('torrents_vinyl',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_lossless': + $Feed->channel('Lossless Torrents', 'RSS feed for all new lossless uploads.'); + $Feed->retrieve('torrents_lossless',$_GET['authkey'],$_GET['passkey']); + break; + case 'torrents_lossless24': + $Feed->channel('24bit Lossless Torrents', 'RSS feed for all new 24bit uploads.'); + $Feed->retrieve('torrents_lossless24',$_GET['authkey'],$_GET['passkey']); + break; + default: + // Personalized torrents + if(empty($_GET['name']) && substr($_GET['feed'], 0, 16) == 'torrents_notify_'){ + // All personalized torrent notifications + $Feed->channel('Personalized torrent notifications', 'RSS feed for personalized torrent notifications.'); + $Feed->retrieve($_GET['feed'],$_GET['authkey'],$_GET['passkey']); + } elseif(!empty($_GET['name']) && substr($_GET['feed'], 0, 16) == 'torrents_notify_'){ + // Specific personalized torrent notification channel + $Feed->channel(display_str($_GET['name']), 'Personal RSS feed: '.display_str($_GET['name'])); + $Feed->retrieve($_GET['feed'],$_GET['authkey'],$_GET['passkey']); + } elseif(!empty($_GET['name']) && substr($_GET['feed'], 0, 21) == 'torrents_bookmarks_t_') { + // Bookmarks + $Feed->channel('Bookmarked torrent notifications', 'RSS feed for bookmarked torrents.'); + $Feed->retrieve($_GET['feed'],$_GET['authkey'],$_GET['passkey']); + } else { + $Feed->channel('All Torrents', 'RSS feed for all new torrent uploads.'); + $Feed->retrieve('torrents_all',$_GET['authkey'],$_GET['passkey']); + } +} +$Feed->close_feed(); +?> diff --git a/sections/forums/add_poll_option.php b/sections/forums/add_poll_option.php new file mode 100644 index 00000000..63176732 --- /dev/null +++ b/sections/forums/add_poll_option.php @@ -0,0 +1,30 @@ +query("SELECT ForumID FROM forums_topics WHERE ID = $ThreadID"); + list($ForumID) = $DB->next_record(); + if(!in_array($ForumID, $ForumsRevealVoters)) { + error(403); + } +} +$DB->query("SELECT Answers FROM forums_polls WHERE TopicID = ".$ThreadID); +if($DB->record_count() < 1) { + error(404); +} + +list($Answers) = $DB->next_record(MYSQLI_NUM, false); +$Answers = unserialize($Answers); +$Answers[] = $NewOption; +$Answers = serialize($Answers); + +$DB->query("UPDATE forums_polls SET Answers = '".db_string($Answers)."' WHERE TopicID = ".$ThreadID); +$Cache->delete_value('polls_'.$ThreadID); + +header("Location: forums.php?action=viewthread&threadid=".$ThreadID); diff --git a/sections/forums/ajax_get_edit.php b/sections/forums/ajax_get_edit.php new file mode 100644 index 00000000..ad01f41b --- /dev/null +++ b/sections/forums/ajax_get_edit.php @@ -0,0 +1,77 @@ +get_value($Type.'_edits_'.$PostID); +if(!is_array($Edits)) { + $DB->query("SELECT ce.EditUser, um.Username, ce.EditTime, ce.Body + FROM comments_edits AS ce + JOIN users_main AS um ON um.ID=ce.EditUser + WHERE Page = '".$Type."' AND PostID = ".$PostID." + ORDER BY ce.EditTime DESC"); + $Edits = $DB->to_array(); + $Cache->cache_value($Type.'_edits_'.$PostID, $Edits, 0); +} + +list($UserID, $Username, $Time) = $Edits[$Depth]; +if($Depth != 0) { + list(,,,$Body) = $Edits[$Depth - 1]; +} else { + //Not an edit, have to get from the original + switch($Type) { + case 'forums' : + //Get from normal forum stuffs + $DB->query("SELECT Body + FROM forums_posts + WHERE ID = ".$PostID); + list($Body) = $DB->next_record(); + break; + case 'collages' : + case 'requests' : + case 'torrents' : + $DB->query("SELECT Body + FROM ".$Type."_comments + WHERE ID = ".$PostID); + list($Body) = $DB->next_record(); + break; + } +} +?> + + full_format($Body)?> +
    +
    + + + « + + + + Original Post + 0) { ?> + » + + diff --git a/sections/forums/catchup.php b/sections/forums/catchup.php new file mode 100644 index 00000000..aa87437e --- /dev/null +++ b/sections/forums/catchup.php @@ -0,0 +1,21 @@ +query("UPDATE users_info SET CatchupTime=NOW() WHERE UserID=$LoggedUser[ID]"); + $Cache->delete_value('user_info_'.$LoggedUser['ID']); + header('Location: forums.php'); + +} else { + // Insert a value for each topic + $DB->query("INSERT INTO forums_last_read_topics (UserID, TopicID, PostID) + SELECT '$LoggedUser[ID]', ID, LastPostID FROM + forums_topics + WHERE (LastPostTime>'".time_minus(3600*24*30)."' OR IsSticky='1') + AND ForumID = ".$_GET['forumid']." + ON DUPLICATE KEY UPDATE PostID=LastPostID"); + + header('Location: forums.php?action=viewforum&forumid='.$_GET['forumid']); +} +?> diff --git a/sections/forums/change_vote.php b/sections/forums/change_vote.php new file mode 100644 index 00000000..5dd8783b --- /dev/null +++ b/sections/forums/change_vote.php @@ -0,0 +1,22 @@ +query("SELECT ForumID FROM forums_topics WHERE ID = $ThreadID"); + list($ForumID) = $DB->next_record(); + if(!in_array($ForumID, $ForumsRevealVoters)) { + error(403); + } + } + + $DB->query("UPDATE forums_polls_votes SET Vote = ".$NewVote." WHERE TopicID = ".$ThreadID." AND UserID = ".$LoggedUser['ID']); + $Cache->delete_value('polls_'.$ThreadID); + header("Location: forums.php?action=viewthread&threadid=".$ThreadID); + +} else { + error(404); +} diff --git a/sections/forums/delete.php b/sections/forums/delete.php new file mode 100644 index 00000000..9dd09261 --- /dev/null +++ b/sections/forums/delete.php @@ -0,0 +1,96 @@ +query("SELECT + DISTINCT + TopicID, + ForumID, + CEIL( + (SELECT COUNT(ID) + FROM forums_posts + WHERE TopicID=p.TopicID)/".POSTS_PER_PAGE." + ) AS Pages, + CEIL( + (SELECT COUNT(ID) + FROM forums_posts + WHERE ID<'$PostID' + AND TopicID=p.TopicID)/".POSTS_PER_PAGE." + ) AS Page + FROM forums_posts AS p + JOIN forums_topics AS t ON t.ID=p.TopicID + WHERE p.TopicID=(SELECT TopicID FROM forums_posts WHERE ID='$PostID')"); +list($TopicID, $ForumID, $Pages, $Page) = $DB->next_record(); + +// $Pages = number of pages in the thread +// $Page = which page the post is on +// These are set for cache clearing. + +$DB->query("DELETE FROM forums_posts WHERE ID='$PostID'"); + +$DB->query("SELECT MAX(ID) FROM forums_posts WHERE TopicID='$TopicID'"); +list($LastID) = $DB->next_record(); +$DB->query("UPDATE forums AS f, forums_topics AS t SET f.NumPosts=f.NumPosts-1, t.NumPosts=t.NumPosts-1 WHERE f.ID='$ForumID' AND t.ID='$TopicID'"); + +if($LastID < $PostID) { // Last post in a topic was removed + $DB->query("SELECT p.AuthorID, u.Username, p.AddedTime FROM forums_posts AS p LEFT JOIN users_main AS u ON u.ID = p.AuthorID WHERE p.ID='$LastID'"); + list($LastAuthorID, $LastAuthorName, $LastTime) = $DB->next_record(); + $DB->query("UPDATE forums_topics SET LastPostID='$LastID', LastPostAuthorID='$LastAuthorID', LastPostTime='$LastTime' WHERE ID='$TopicID'"); + $DB->query("SELECT + t.ID, t.Title, t.LastPostID, t.LastPostTime, t.LastPostAuthorID, u.Username + FROM forums_topics AS t + LEFT JOIN users_main AS u ON u.ID = t.LastPostAuthorID + WHERE ForumID='$ForumID' AND t.ID<>'$TopicID' + ORDER BY LastPostID DESC LIMIT 1"); + list($LastTopicID, $LastTopicTitle, $LastTopicPostID, $LastTopicPostTime, $LastTopicAuthorID, $LastTopicAuthorName) = $DB->next_record(MYSQLI_BOTH, false); + + if($LastID < $LastTopicPostID) { // Topic is no longer the most recent in its forum + $DB->query("UPDATE forums SET LastPostTopicID='$LastTopicID', LastPostID='$LastTopicPostID', LastPostAuthorID='$LastTopicAuthorID', LastPostTime='$LastTopicPostTime' WHERE ID='$ForumID' AND LastPostTopicID='$TopicID'"); + $UpdateArrayForums = array( + 'NumPosts' => '-1', + 'LastPostID' => $LastTopicPostID, + 'LastPostAuthorID' => $LastTopicAuthorID, + 'Username' => $LastTopicAuthorName, + 'LastPostTime' => $LastTopicPostTime, + 'LastPostTopicID' => $LastTopicID, + 'Title' => $LastTopicTitle); + } else { // Topic is still the most recent in its forum + $DB->query("UPDATE forums SET LastPostID='$LastID', LastPostAuthorID='$LastAuthorID', LastPostTime='$LastTime' WHERE ID='$ForumID' AND LastPostTopicID='$TopicID'"); + $UpdateArrayForums = array( + 'NumPosts' => '-1', + 'LastPostID' => $LastID, + 'LastPostAuthorID' => $LastAuthorID, + 'Username' => $LastAuthorName, + 'LastPostTime' => $LastTime); + } + $UpdateArrayThread = array('Posts' => '-1', 'LastPostAuthorID' => $LastAuthorID); +} else { + $UpdateArrayForums = array('NumPosts' => '-1'); + $UpdateArrayThread = array('Posts' => '-1'); +} + +//We need to clear all subsequential catalogues as they've all been bumped with the absence of this post +$ThisCatalogue = floor((POSTS_PER_PAGE*$Page-POSTS_PER_PAGE)/THREAD_CATALOGUE); +$LastCatalogue = floor((POSTS_PER_PAGE*$Pages-POSTS_PER_PAGE)/THREAD_CATALOGUE); +for($i=$ThisCatalogue;$i<=$LastCatalogue;$i++) { + $Cache->delete('thread_'.$TopicID.'_catalogue_'.$i); +} + +$Cache->begin_transaction('thread_'.$TopicID.'_info'); +$Cache->update_row(false, $UpdateArrayThread); +$Cache->commit_transaction(); + +$Cache->begin_transaction('forums_list'); +$Cache->update_row($ForumID, $UpdateArrayForums); +$Cache->commit_transaction(); + +$Cache->delete('forums_'.$ForumID); +?> diff --git a/sections/forums/delete_poll_option.php b/sections/forums/delete_poll_option.php new file mode 100644 index 00000000..e67a971a --- /dev/null +++ b/sections/forums/delete_poll_option.php @@ -0,0 +1,35 @@ +query("SELECT ForumID FROM forums_topics WHERE ID = $ThreadID"); + list($ForumID) = $DB->next_record(); + if(!in_array($ForumID, $ForumsRevealVoters)) { + error(403); + } + + $DB->query("SELECT Answers FROM forums_polls WHERE TopicID = ".$ThreadID); + if($DB->record_count() < 1) { + error(404); + } + + list($Answers) = $DB->next_record(MYSQLI_NUM, false); + $Answers = unserialize($Answers); + unset($Answers[$PollOption]); + $Answers = serialize($Answers); + + $DB->query("UPDATE forums_polls SET Answers = '".db_string($Answers)."' WHERE TopicID = ".$ThreadID); + $DB->query("DELETE FROM forums_polls_votes WHERE Vote = ".$PollOption." AND TopicID = ".$ThreadID); + + $Cache->delete_value('polls_'.$ThreadID); + header("Location: forums.php?action=viewthread&threadid=".$ThreadID); + +} else { + error(404); +} diff --git a/sections/forums/edit_rules.php b/sections/forums/edit_rules.php new file mode 100644 index 00000000..73a15c0a --- /dev/null +++ b/sections/forums/edit_rules.php @@ -0,0 +1,72 @@ +query("INSERT INTO forums_specific_rules (ForumID, ThreadID) VALUES (".$ForumID.", ".$_POST['new_thread'].")"); + } + } + if(!empty($_POST['del'])) { + if(is_number($_POST['threadid'])) { + $DB->query("DELETE FROM forums_specific_rules WHERE ForumID = ".$ForumID." AND ThreadID = ".$_POST['threadid']); + } + } + $Cache->delete_value('forums_list'); +} + + +$DB->query("SELECT ThreadID FROM forums_specific_rules WHERE ForumID = ".$ForumID); +$ThreadIDs = $DB->collect('ThreadID'); + +show_header(); +?> +
    +

    + Forums + > + + > + Edit forum specific rules +

    + + + + + + + + + + + + + + + + +
    Thread ID
    + + + +
    +
    + + +
    +
    +
    + diff --git a/sections/forums/forum.php b/sections/forums/forum.php new file mode 100644 index 00000000..d37cea46 --- /dev/null +++ b/sections/forums/forum.php @@ -0,0 +1,236 @@ +get_value('forums_'.$ForumID); +} +if(!isset($Forum) || !is_array($Forum)) { + $DB->query("SELECT + t.ID, + t.Title, + t.AuthorID, + author.Username AS AuthorUsername, + t.IsLocked, + t.IsSticky, + t.NumPosts, + t.LastPostID, + t.LastPostTime, + t.LastPostAuthorID, + last_author.Username AS LastPostUsername + FROM forums_topics AS t + LEFT JOIN users_main AS last_author ON last_author.ID = t.LastPostAuthorID + LEFT JOIN users_main AS author ON author.ID = t.AuthorID + WHERE t.ForumID = '$ForumID' + ORDER BY t.IsSticky DESC, t.LastPostTime DESC + LIMIT $Limit"); // Can be cached until someone makes a new post + $Forum = $DB->to_array('ID',MYSQLI_ASSOC); + if($Page==1) { + $DB->query("SELECT COUNT(ID) FROM forums_topics WHERE ForumID='$ForumID' AND IsSticky='1'"); + list($Stickies) = $DB->next_record(); + $Cache->cache_value('forums_'.$ForumID, array($Forum,'',0,$Stickies), 0); + } +} + +if(!isset($Forums[$ForumID])) { error(404); } +// Make sure they're allowed to look at the page +if (!check_perms('site_moderate_forums')) { + if (isset($LoggedUser['CustomForums'][$ForumID]) && $LoggedUser['CustomForums'][$ForumID] === 0) { error(403); } +} +if($LoggedUser['CustomForums'][$ForumID] != 1 && $Forums[$ForumID]['MinClassRead'] > $LoggedUser['Class']) { error(403); } + +// Start printing +show_header('Forums > '. $Forums[$ForumID]['Name']); +?> +
    +

    Forums >

    + + + + + + + + + + + + + + + + + + + +query('SELECT + l.TopicID, + l.PostID, + CEIL((SELECT COUNT(ID) FROM forums_posts WHERE forums_posts.TopicID = l.TopicID AND forums_posts.ID<=l.PostID)/'.$PerPage.') AS Page + FROM forums_last_read_topics AS l + WHERE TopicID IN('.implode(', ', array_keys($Forum)).') AND + UserID=\''.$LoggedUser['ID'].'\''); + + // Turns the result set into a multi-dimensional array, with + // forums_last_read_topics.TopicID as the key. + // This is done here so we get the benefit of the caching, and we + // don't have to make a database query for each topic on the page + $LastRead = $DB->to_array('TopicID'); + + //---------- Begin printing + + $Row='a'; + foreach($Forum as $Topic){ + list($TopicID, $Title, $AuthorID, $AuthorName, $Locked, $Sticky, $PostCount, $LastID, $LastTime, $LastAuthorID, $LastAuthorName) = array_values($Topic); + $Row = ($Row == 'a') ? 'b' : 'a'; + + // Build list of page links + // Only do this if there is more than one page + $PageLinks = array(); + $ShownEllipses = false; + $PagesText = ''; + $TopicPages = ceil($PostCount/$PerPage); + + if($TopicPages > 1){ + $PagesText=' ('; + for($i = 1; $i <= $TopicPages; $i++){ + if($TopicPages>4 && ($i > 2 && $i <= $TopicPages-2)) { + if(!$ShownEllipses) { + $PageLinks[]='-'; + $ShownEllipses = true; + } + continue; + } + $PageLinks[]=''.$i.''; + } + $PagesText.=implode(' ', $PageLinks); + $PagesText.=')'; + } + + // handle read/unread posts - the reason we can't cache the whole page + if((!$Locked || $Sticky) && ((empty($LastRead[$TopicID]) || $LastRead[$TopicID]['PostID']<$LastID) && strtotime($LastTime)>$LoggedUser['CatchupTime'])) { + $Read = 'unread'; + } else { + $Read = 'read'; + } + if($Locked) { $Read .= "_locked"; } + if($Sticky) { $Read .= "_sticky"; } +?> + + + + + + + +
    LatestRepliesAuthor
    + No threads to display in this forum! +
    + + + + + + + + + + + + + + by + +
    + + + +
    + diff --git a/sections/forums/functions.php b/sections/forums/functions.php new file mode 100644 index 00000000..dd6c6757 --- /dev/null +++ b/sections/forums/functions.php @@ -0,0 +1,57 @@ +get_value('thread_'.$ThreadID.'_info')) { + $DB->query("SELECT + t.Title, + t.ForumID, + t.IsLocked, + t.IsSticky, + COUNT(fp.id) AS Posts, + t.LastPostAuthorID, + ISNULL(p.TopicID) AS NoPoll, + t.StickyPostID + FROM forums_topics AS t + JOIN forums_posts AS fp ON fp.TopicID = t.ID + LEFT JOIN forums_polls AS p ON p.TopicID=t.ID + WHERE t.ID = '$ThreadID' + GROUP BY fp.TopicID"); + if($DB->record_count()==0) { error(404); } + $ThreadInfo = $DB->next_record(MYSQLI_ASSOC); + if($ThreadInfo['StickyPostID']) { + $ThreadInfo['Posts']--; + $DB->query("SELECT + p.ID, + p.AuthorID, + p.AddedTime, + p.Body, + p.EditedUserID, + p.EditedTime, + ed.Username + FROM forums_posts as p + LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID + WHERE p.TopicID = '$ThreadID' AND p.ID = '".$ThreadInfo['StickyPostID']."'"); + list($ThreadInfo['StickyPost']) = $DB->to_array(false, MYSQLI_ASSOC); + } + if(!$SelectiveCache || !$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) { + $Cache->cache_value('thread_'.$ThreadID.'_info', $ThreadInfo, 0); + } + } + if($Return) { + return $ThreadInfo; + } +} + +function check_forumperm($ForumID, $Perm = 'Read') { + global $LoggedUser, $Forums; + if ($LoggedUser['CustomForums'][$ForumID] == 1) { + return true; + } + if($Forums[$ForumID]['MinClass'.$Perm] > $LoggedUser['Class'] && (!isset($LoggedUser['CustomForums'][$ForumID]) || $LoggedUser['CustomForums'][$ForumID] == 0)) { + return false; + } + if(isset($LoggedUser['CustomForums'][$ForumID]) && $LoggedUser['CustomForums'][$ForumID] == 0) { + return false; + } + return true; +} diff --git a/sections/forums/get_post.php b/sections/forums/get_post.php new file mode 100644 index 00000000..496efd44 --- /dev/null +++ b/sections/forums/get_post.php @@ -0,0 +1,38 @@ +query("SELECT + p.Body, t.ForumID + FROM forums_posts as p JOIN forums_topics as t on p.TopicID = t.ID + WHERE p.ID='$PostID'"); +list($Body, $ForumID) = $DB->next_record(MYSQLI_NUM); + +// Is the user allowed to view the post? +if(!check_forumperm($ForumID)) { + error(0); +} + +// This gets sent to the browser, which echoes it wherever + +echo trim($Body); + +?> \ No newline at end of file diff --git a/sections/forums/index.php b/sections/forums/index.php new file mode 100644 index 00000000..2930de19 --- /dev/null +++ b/sections/forums/index.php @@ -0,0 +1,169 @@ +get_value('forums_categories'); +if ($ForumCats === false) { + $DB->query("SELECT ID, Name FROM forums_categories"); + $ForumCats = array(); + while (list($ID, $Name) = $DB->next_record()) { + $ForumCats[$ID] = $Name; + } + $Cache->cache_value('forums_categories', $ForumCats, 0); //Inf cache. +} + +//This variable contains all our lovely forum data +if(!$Forums = $Cache->get_value('forums_list')) { + $DB->query("SELECT + f.ID, + f.CategoryID, + f.Name, + f.Description, + f.MinClassRead, + f.MinClassWrite, + f.MinClassCreate, + f.NumTopics, + f.NumPosts, + f.LastPostID, + f.LastPostAuthorID, + um.Username, + f.LastPostTopicID, + f.LastPostTime, + COUNT(sr.ThreadID) AS SpecificRules, + t.Title, + t.IsLocked, + t.IsSticky + FROM forums AS f + JOIN forums_categories AS fc ON fc.ID = f.CategoryID + LEFT JOIN forums_topics as t ON t.ID = f.LastPostTopicID + LEFT JOIN users_main AS um ON um.ID=f.LastPostAuthorID + LEFT JOIN forums_specific_rules AS sr ON sr.ForumID = f.ID + GROUP BY f.ID + ORDER BY fc.Sort, fc.Name, f.CategoryID, f.Sort"); + $Forums = $DB->to_array('ID', MYSQLI_ASSOC, false); + foreach($Forums as $ForumID => $Forum) { + if(count($Forum['SpecificRules'])) { + $DB->query("SELECT ThreadID FROM forums_specific_rules WHERE ForumID = ".$ForumID); + $ThreadIDs = $DB->collect('ThreadID'); + $Forums[$ForumID]['SpecificRules'] = $ThreadIDs; + } + } + unset($ForumID, $Forum); + $Cache->cache_value('forums_list', $Forums, 0); //Inf cache. +} + +if(!empty($_POST['action'])){ + switch ($_POST['action']) { + case 'reply': + require(SERVER_ROOT.'/sections/forums/take_reply.php'); + break; + case 'new': + require(SERVER_ROOT.'/sections/forums/take_new_thread.php'); + break; + case 'mod_thread': + require(SERVER_ROOT.'/sections/forums/mod_thread.php'); + break; + case 'poll_mod': + require(SERVER_ROOT.'/sections/forums/poll_mod.php'); + break; + case 'add_poll_option': + require(SERVER_ROOT.'/sections/forums/add_poll_option.php'); + break; + default: + error(0); + } +} elseif(!empty($_GET['action'])) { + switch ($_GET['action']) { + case 'viewforum': + // Page that lists all the topics in a forum + require(SERVER_ROOT.'/sections/forums/forum.php'); + break; + case 'viewthread': + case 'viewtopic': + // Page that displays threads + require(SERVER_ROOT.'/sections/forums/thread.php'); + break; + case 'ajax_get_edit': + // Page that switches edits for mods + require(SERVER_ROOT.'/sections/forums/ajax_get_edit.php'); + break; + case 'new': + // Create a new thread + require(SERVER_ROOT.'/sections/forums/newthread.php'); + break; + case 'takeedit': + // Edit posts + require(SERVER_ROOT.'/sections/forums/takeedit.php'); + break; + case 'get_post': + // Get posts + require(SERVER_ROOT.'/sections/forums/get_post.php'); + break; + case 'delete': + // Delete posts + require(SERVER_ROOT.'/sections/forums/delete.php'); + break; + case 'catchup': + // Catchup + require(SERVER_ROOT.'/sections/forums/catchup.php'); + break; + case 'search': + // Search posts + require(SERVER_ROOT.'/sections/forums/search.php'); + break; + case 'change_vote': + // Change poll vote + require(SERVER_ROOT.'/sections/forums/change_vote.php'); + break; + case 'delete_poll_option': + require(SERVER_ROOT.'/sections/forums/delete_poll_option.php'); + break; + case 'sticky_post': + require(SERVER_ROOT.'/sections/forums/sticky_post.php'); + break; + case 'edit_rules': + require(SERVER_ROOT.'/sections/forums/edit_rules.php'); + break; + case 'thread_subscribe': + break; + default: + error(404); + } +} else { + require(SERVER_ROOT.'/sections/forums/main.php'); +} + +// Function to get basic information on a forum +// Uses class CACHE +function get_forum_info($ForumID) { + global $DB, $Cache; + $Forum = $Cache->get_value('ForumInfo_'.$ForumID); + if(!$Forum) { + $DB->query("SELECT + Name, + MinClassRead, + MinClassWrite, + MinClassCreate, + COUNT(forums_topics.ID) AS Topics + FROM forums + LEFT JOIN forums_topics ON forums_topics.ForumID=forums.ID + WHERE forums.ID='$ForumID' + GROUP BY ForumID"); + if($DB->record_count() == 0) { + return false; + } + // Makes an array, with $Forum['Name'], etc. + $Forum = $DB->next_record(MYSQLI_ASSOC); + + $Cache->cache_value('ForumInfo_'.$ForumID, $Forum, 86400); // Cache for a day + } + return $Forum; +} diff --git a/sections/forums/main.php b/sections/forums/main.php new file mode 100644 index 00000000..20d3bf2c --- /dev/null +++ b/sections/forums/main.php @@ -0,0 +1,111 @@ +query("SELECT + l.TopicID, + l.PostID, + CEIL((SELECT COUNT(ID) FROM forums_posts WHERE forums_posts.TopicID = l.TopicID AND forums_posts.ID<=l.PostID)/$PerPage) AS Page + FROM forums_last_read_topics AS l + WHERE TopicID IN(".implode(',',$TopicIDs).") AND + UserID='$LoggedUser[ID]'"); + $LastRead = $DB->to_array('TopicID', MYSQLI_ASSOC); +} else { + $LastRead = array(); +} + +show_header('Forums'); +?> +
    +

    Forums

    +query("SELECT RestrictedForums FROM users_info WHERE UserID = ".$LoggedUser['ID']); +list($RestrictedForums) = $DB->next_record(); +$RestrictedForums = explode(',', $RestrictedForums); +$PermittedForums = array_keys($LoggedUser['PermittedForums']); +foreach ($Forums as $Forum) { + list($ForumID, $CategoryID, $ForumName, $ForumDescription, $MinRead, $MinWrite, $MinCreate, $NumTopics, $NumPosts, $LastPostID, $LastAuthorID, $LastPostAuthorName, $LastTopicID, $LastTime, $SpecificRules, $LastTopic, $Locked, $Sticky) = array_values($Forum); + if ($LoggedUser['CustomForums'][$ForumID] != 1 && ($MinRead>$LoggedUser['Class'] || array_search($ForumID, $RestrictedForums) !== FALSE)) { + continue; + } + $Row = ($Row == 'a') ? 'b' : 'a'; + $ForumDescription = display_str($ForumDescription); + + if($CategoryID!=$LastCategoryID) { + $Row = 'b'; + $LastCategoryID=$CategoryID; + if($OpenTable) { ?> + + +

    + + + + + + + + +$LoggedUser['CatchupTime'])) { + $Read = 'unread'; + } else { + $Read = 'read'; + } +/* Removed per request, as distracting + if($Locked) { $Read .= "_locked"; } + if($Sticky) { $Read .= "_sticky"; } +*/ +?> + + + + + + + + + + + + +
    ForumLast PostTopicsPosts
    +

    + +

    +
    + There are no topics here'.'create one'.'' : ''?>. + + + + + + + + + + by +
    + +
    +query("DELETE FROM forums_last_read_topics WHERE TopicID='$TopicID'"); +} + +$DB->query("SELECT + t.ForumID, + f.MinClassWrite, + COUNT(p.ID) AS Posts + FROM forums_topics AS t + LEFT JOIN forums_posts AS p ON p.TopicID=t.ID + LEFT JOIN forums AS f ON f.ID=.t.ForumID + WHERE t.ID='$TopicID' + GROUP BY p.TopicID"); +list($OldForumID, $MinClassWrite, $Posts) = $DB->next_record(); + +if($MinClassWrite > $LoggedUser['Class']) { error(403); } + +// If we're moving +$Cache->delete_value('forums_'.$ForumID); +$Cache->delete_value('forums_'.$OldForumID); + +// If we're deleting a thread +if(isset($_POST['delete'])) { + if(check_perms('site_admin_forums')) { + $DB->query("DELETE FROM forums_posts WHERE TopicID='$TopicID'"); + $DB->query("DELETE FROM forums_topics WHERE ID='$TopicID'"); + + $DB->query("SELECT + t.ID, + t.LastPostID, + t.Title, + p.AuthorID, + um.Username, + p.AddedTime, + (SELECT COUNT(pp.ID) FROM forums_posts AS pp JOIN forums_topics AS tt ON pp.TopicID=tt.ID WHERE tt.ForumID='$ForumID'), + t.IsLocked, + t.IsSticky + FROM forums_topics AS t + JOIN forums_posts AS p ON p.ID=t.LastPostID + LEFT JOIN users_main AS um ON um.ID=p.AuthorID + WHERE t.ForumID='$ForumID' + GROUP BY t.ID + ORDER BY t.LastPostID DESC LIMIT 1"); + list($NewLastTopic, $NewLastPostID, $NewLastTitle, $NewLastAuthorID, $NewLastAuthorName, $NewLastAddedTime, $NumPosts, $NewLocked, $NewSticky) = $DB->next_record(MYSQLI_BOTH, false); + + $DB->query("UPDATE forums SET + NumTopics=NumTopics-1, + NumPosts=NumPosts-'$Posts', + LastPostTopicID='$NewLastTopic', + LastPostID='$NewLastPostID', + LastPostAuthorID='$NewLastAuthorID', + LastPostTime='$NewLastAddedTime' + WHERE ID='$ForumID'"); + + $Cache->delete('thread_'.$TopicID); + + + $Cache->begin_transaction('forums_list'); + $UpdateArray = array( + 'NumPosts'=>$NumPosts, + 'NumTopics'=>'-1', + 'LastPostID'=>$NewLastPostID, + 'LastPostAuthorID'=>$NewLastAuthorID, + 'Username'=>$NewLastAuthorName, + 'LastPostTopicID'=>$NewLastTopic, + 'LastPostTime'=>$NewLastAddedTime, + 'Title'=>$NewLastTitle, + 'IsLocked'=>$NewLocked, + 'IsSticky'=>$NewSticky + ); + + $Cache->update_row($ForumID, $UpdateArray); + $Cache->commit_transaction(0); + $Cache->delete_value('thread_'.$TopicID.'_info'); + + header('Location: forums.php?action=viewforum&forumid='.$ForumID); + } else { + error(403); + } + +} else { // If we're just editing it + $Cache->begin_transaction('thread_'.$TopicID.'_info'); + $UpdateArray = array( + 'IsSticky'=>$Sticky, + 'IsLocked'=>$Locked, + 'Title'=>cut_string($_POST['title'], 150, 1, 0), + 'ForumID'=>$ForumID + ); + $Cache->update_row(false, $UpdateArray); + $Cache->commit_transaction(0); + + $DB->query("UPDATE forums_topics SET + IsSticky = '$Sticky', + IsLocked = '$Locked', + Title = '$Title', + ForumID ='$ForumID' + WHERE ID='$TopicID'"); + + + if($ForumID!=$OldForumID) { // If we're moving a thread, change the forum stats + + $DB->query("SELECT MinClassRead, MinClassWrite, Name FROM forums WHERE ID='$ForumID'"); + list($MinClassRead, $MinClassWrite, $ForumName) = $DB->next_record(); + $Cache->begin_transaction('thread_'.$TopicID.'_info'); + $UpdateArray = array( + 'ForumName'=>$ForumName, + 'MinClassRead'=>$MinClassRead, + 'MinClassWrite'=>$MinClassWrite + ); + $Cache->update_row(false, $UpdateArray); + $Cache->commit_transaction(3600*24*5); + + $Cache->begin_transaction('forums_list'); + + + // Forum we're moving from + $DB->query("SELECT + t.ID, + t.LastPostID, + t.Title, + p.AuthorID, + um.Username, + p.AddedTime, + (SELECT COUNT(pp.ID) FROM forums_posts AS pp JOIN forums_topics AS tt ON pp.TopicID=tt.ID WHERE tt.ForumID='$OldForumID'), + t.IsLocked, + t.IsSticky + FROM forums_topics AS t + JOIN forums_posts AS p ON p.ID=t.LastPostID + LEFT JOIN users_main AS um ON um.ID=p.AuthorID + WHERE t.ForumID='$OldForumID' + ORDER BY t.LastPostID DESC LIMIT 1"); + list($NewLastTopic, $NewLastPostID, $NewLastTitle, $NewLastAuthorID, $NewLastAuthorName, $NewLastAddedTime, $NumPosts, $NewLocked, $NewSticky) = $DB->next_record(MYSQLI_NUM, false); + + $DB->query("UPDATE forums SET + NumTopics=NumTopics-1, + NumPosts=NumPosts-'$Posts', + LastPostTopicID='$NewLastTopic', + LastPostID='$NewLastPostID', + LastPostAuthorID='$NewLastAuthorID', + LastPostTime='$NewLastAddedTime' + WHERE ID='$OldForumID'"); + + + $UpdateArray = array( + 'NumPosts'=>$NumPosts, + 'NumTopics'=>'-1', + 'LastPostID'=>$NewLastPostID, + 'LastPostAuthorID'=>$NewLastAuthorID, + 'Username'=>$NewLastAuthorName, + 'LastPostTopicID'=>$NewLastTopic, + 'LastPostTime'=>$NewLastAddedTime, + 'Title'=>$NewLastTitle, + 'IsLocked'=>$NewLocked, + 'IsSticky'=>$NewSticky + ); + + + $Cache->update_row($OldForumID, $UpdateArray); + + // Forum we're moving to + + $DB->query("SELECT + t.ID, + t.LastPostID, + t.Title, + p.AuthorID, + um.Username, + p.AddedTime, + (SELECT COUNT(pp.ID) FROM forums_posts AS pp JOIN forums_topics AS tt ON pp.TopicID=tt.ID WHERE tt.ForumID='$ForumID') + FROM forums_topics AS t + JOIN forums_posts AS p ON p.ID=t.LastPostID + LEFT JOIN users_main AS um ON um.ID=p.AuthorID + WHERE t.ForumID='$ForumID' + ORDER BY t.LastPostID DESC LIMIT 1"); + list($NewLastTopic, $NewLastPostID, $NewLastTitle, $NewLastAuthorID, $NewLastAuthorName, $NewLastAddedTime, $NumPosts) = $DB->next_record(); + + $DB->query("UPDATE forums SET + NumTopics=NumTopics+1, + NumPosts=NumPosts+'$Posts', + LastPostTopicID='$NewLastTopic', + LastPostID='$NewLastPostID', + LastPostAuthorID='$NewLastAuthorID', + LastPostTime='$NewLastAddedTime' + WHERE ID='$ForumID'"); + + + $UpdateArray = array( + 'NumPosts'=>($NumPosts+$Posts), + 'NumTopics'=>'+1', + 'LastPostID'=>$NewLastPostID, + 'LastPostAuthorID'=>$NewLastAuthorID, + 'Username'=>$NewLastAuthorName, + 'LastPostTopicID'=>$NewLastTopic, + 'LastPostTime'=>$NewLastAddedTime, + 'Title'=>$NewLastTitle + ); + + + $Cache->update_row($ForumID, $UpdateArray); + + $Cache->commit_transaction(0); + } else { // Editing + $DB->query("SELECT LastPostTopicID FROM forums WHERE ID='$ForumID'"); + list($LastTopicID) = $DB->next_record(); + if($LastTopicID == $TopicID) { + $UpdateArray = array( + 'Title'=>$_POST['title'], + 'IsLocked'=>$Locked, + 'IsSticky'=>$Sticky + ); + $Cache->begin_transaction('forums_list'); + $Cache->update_row($ForumID, $UpdateArray); + $Cache->commit_transaction(0); + } + } + if($Locked) { + $CatalogueID = floor($NumPosts/THREAD_CATALOGUE); + for($i=0;$i<=$CatalogueID;$i++) { + $Cache->expire_value('thread_'.$TopicID.'_catalogue_'.$i,3600*24*7); + } + $Cache->expire_value('thread_'.$TopicID.'_info',3600*24*7); + + $DB->query('UPDATE forums_polls SET Closed=\'0\' WHERE TopicID=\''.$TopicID.'\''); + $Cache->delete_value('polls_'.$TopicID); + } + header('Location: forums.php?action=viewthread&threadid='.$TopicID.'&page='.$Page); +} diff --git a/sections/forums/newthread.php b/sections/forums/newthread.php new file mode 100644 index 00000000..d3c3c24b --- /dev/null +++ b/sections/forums/newthread.php @@ -0,0 +1,149 @@ + '.$Forum['Name'].' > New Topic','comments,bbcode'); +?> +
    +

    Forums > > New Topic

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Title
    Body
    + onchange="$('#subscribeboxpreview').raw().checked=this.checked;" /> + +
    + Poll Settings + (View) +
    + + + + +
    +
    +
    + diff --git a/sections/forums/poll_mod.php b/sections/forums/poll_mod.php new file mode 100644 index 00000000..df05a6e0 --- /dev/null +++ b/sections/forums/poll_mod.php @@ -0,0 +1,45 @@ +get_value('polls_'.$TopicID)) { + $DB->query("SELECT Question, Answers, Featured, Closed FROM forums_polls WHERE TopicID='".$TopicID."'"); + list($Question, $Answers, $Featured, $Closed) = $DB->next_record(MYSQLI_NUM, array(1)); + $Answers = unserialize($Answers); + $DB->query("SELECT Vote, COUNT(UserID) FROM forums_polls_votes WHERE TopicID='$TopicID' AND Vote <> '0' GROUP BY Vote"); + $VoteArray = $DB->to_array(false, MYSQLI_NUM); + + $Votes = array(); + foreach ($VoteArray as $VoteSet) { + list($Key,$Value) = $VoteSet; + $Votes[$Key] = $Value; + } + + for ($i = 1, $il = count($Answers); $i <= $il; ++$i) { + if (!isset($Votes[$i])) { + $Votes[$i] = 0; + } + } +} + +if (isset($_POST['feature'])) { + if (!$Featured || $Featured == '0000-00-00 00:00:00') { + $Featured = sqltime(); + $Cache->cache_value('polls_featured',$TopicID,0); + $DB->query('UPDATE forums_polls SET Featured=\''.sqltime().'\' WHERE TopicID=\''.$TopicID.'\''); + } +} + +if (isset($_POST['close'])) { + $Closed = !$Closed; + $DB->query('UPDATE forums_polls SET Closed=\''.$Closed.'\' WHERE TopicID=\''.$TopicID.'\''); +} + +$Cache->cache_value('polls_'.$TopicID, array($Question,$Answers,$Votes,$Featured,$Closed), 0); + +header('Location: '.$_SERVER['HTTP_REFERER']); +die(); diff --git a/sections/forums/poll_vote.php b/sections/forums/poll_vote.php new file mode 100644 index 00000000..29a8028a --- /dev/null +++ b/sections/forums/poll_vote.php @@ -0,0 +1,145 @@ +get_value('thread_'.$TopicID.'_info')) { + $DB->query("SELECT + t.Title, + t.ForumID, + t.IsLocked, + t.IsSticky, + COUNT(fp.id) AS Posts, + t.LastPostAuthorID, + ISNULL(p.TopicID) AS NoPoll + FROM forums_topics AS t + JOIN forums_posts AS fp ON fp.TopicID = t.ID + LEFT JOIN forums_polls AS p ON p.TopicID=t.ID + WHERE t.ID = '$TopicID' + GROUP BY fp.TopicID"); + if($DB->record_count()==0) { die(); } + $ThreadInfo = $DB->next_record(MYSQLI_ASSOC); + if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) { + $Cache->cache_value('thread_'.$TopicID.'_info', $ThreadInfo, 0); + } +} +$ForumID = $ThreadInfo['ForumID']; + +if (!list($Question,$Answers,$Votes,$Featured,$Closed) = $Cache->get_value('polls_'.$TopicID)) { + $DB->query("SELECT Question, Answers, Featured, Closed FROM forums_polls WHERE TopicID='".$TopicID."'"); + list($Question, $Answers, $Featured, $Closed) = $DB->next_record(MYSQLI_NUM, array(1)); + $Answers = unserialize($Answers); + $DB->query("SELECT Vote, COUNT(UserID) FROM forums_polls_votes WHERE TopicID='$TopicID' AND Vote <> '0' GROUP BY Vote"); + $VoteArray = $DB->to_array(false, MYSQLI_NUM); + + $Votes = array(); + foreach ($VoteArray as $VoteSet) { + list($Key,$Value) = $VoteSet; + $Votes[$Key] = $Value; + } + + for ($i = 1, $il = count($Answers); $i <= $il; ++$i) { + if (!isset($Votes[$i])) { + $Votes[$i] = 0; + } + } + $Cache->cache_value('polls_'.$TopicID, array($Question,$Answers,$Votes,$Featured,$Closed), 0); +} + + +if ($Closed) { + error(403,true); +} + +if (!empty($Votes)) { + $TotalVotes = array_sum($Votes); + $MaxVotes = max($Votes); +} else { + $TotalVotes = 0; + $MaxVotes = 0; +} + +if (!isset($_POST['vote']) || !is_number($_POST['vote'])) { +?> +Please select an option.
    +
    + + + + + + +
    + +


    + +
    +query('INSERT IGNORE INTO forums_polls_votes (TopicID, UserID, Vote) VALUES ('.$TopicID.','.$LoggedUser['ID'].','.$Vote.')'); + if ($DB->affected_rows() == 1 && $Vote != 0) { + $Cache->begin_transaction('polls_'.$TopicID); + $Cache->update_row(2, array($Vote => '+1')); + $Cache->commit_transaction(0); + $Votes[$Vote]++; + $TotalVotes++; + $MaxVotes++; + } + + if ($Vote != 0) { + $Answers[$Vote] = '=> '.$Answers[$Vote]; + } + +?> +
      + 0) { + $Ratio = $Votes[$i]/$MaxVotes; + $Percent = $Votes[$i]/$TotalVotes; + } else { + $Ratio=0; + $Percent=0; + } +?> +
    • (%)
    • +
    • + + + +
    • +query("SELECT GROUP_CONCAT(um.Username SEPARATOR ', '), + fpv.Vote + FROM users_main AS um + JOIN forums_polls_votes AS fpv ON um.ID = fpv.UserID + WHERE TopicID = ".$TopicID." + GROUP BY fpv.Vote"); + + $StaffVotes = $DB->to_array(); + foreach($StaffVotes as $StaffVote) { + list($StaffString, $StaffVoted) = $StaffVote; +?> +
    • -
    • + +
    +
    Votes: +query("SELECT ID FROM users_main WHERE Username='".db_string($User)."'"); + list($AuthorID) = $DB->next_record(); +} else { + $User = ''; +} + +// Are we looking in individual forums? +if(isset($_GET['forums']) && is_array($_GET['forums'])) { + $ForumArray = array(); + foreach($_GET['forums'] as $Forum) { + if(is_number($Forum)) { + $ForumArray[]=$Forum; + } + } + if(count($ForumArray)>0) { + $SearchForums = implode(', ',$ForumArray); + } +} + +// Searching for posts in a specific thread +if(!empty($_GET['threadid'])) { + $ThreadID = db_string($_GET['threadid']); + $Type='body'; + $SQL = "SELECT Title FROM forums_topics AS t + JOIN forums AS f ON f.ID=t.ForumID + WHERE f.MinClassRead <= '$LoggedUser[Class]' + AND t.ID=$ThreadID"; + if(!empty($RestrictedForums)) { + $SQL .= " AND f.ID NOT IN ('".$RestrictedForums."')"; + } + $DB->query($SQL); + if (list($Title) = $DB->next_record()) { + $Title = " > $Title"; + } else { + $Title = ''; + $ThreadID = ''; + } +} else { + $ThreadID = ''; +} + +// Let's hope we got some results - start printing out the content. +show_header('Forums'.' > '.'Search'); +?> +
    +

    Forums > Search

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Search for: + +
    Search in: + /> + + /> + +
    Forums: + + + + + + + + + + + + + + + + + + + + + +
    + /> + +
    +
    Username: + +
    + +
    +
    + + + + + + + +record_count() == 0) { ?> + +next_record()) { + $Row = ($Row == 'a') ? 'b' : 'a'; + // Print results +?> + + + + + + +
    ForumTime
    Nothing found!
    + + + + + + + + + + + +
    + + +
    + diff --git a/sections/forums/sticky_post.php b/sections/forums/sticky_post.php new file mode 100644 index 00000000..da9d1212 --- /dev/null +++ b/sections/forums/sticky_post.php @@ -0,0 +1,23 @@ +query("UPDATE forums_topics SET StickyPostID = 0 WHERE ID = ".$ThreadID); +} else { + $DB->query("UPDATE forums_topics SET StickyPostID = ".$PostID." WHERE ID = ".$ThreadID); +} +$Cache->delete_value('thread_'.$ThreadID.'_info'); + +header('Location: forums.php?action=viewthread&threadid='.$ThreadID); diff --git a/sections/forums/take_new_thread.php b/sections/forums/take_new_thread.php new file mode 100644 index 00000000..d74de848 --- /dev/null +++ b/sections/forums/take_new_thread.php @@ -0,0 +1,191 @@ +query("INSERT INTO forums_topics + (Title, AuthorID, ForumID, LastPostTime, LastPostAuthorID) + Values + ('".db_string($Title)."', '".$LoggedUser['ID']."', '$ForumID', '".sqltime()."', '".$LoggedUser['ID']."')"); +$TopicID = $DB->inserted_id(); + +$DB->query("INSERT INTO forums_posts + (TopicID, AuthorID, AddedTime, Body) + VALUES + ('$TopicID', '".$LoggedUser['ID']."', '".sqltime()."', '".db_string($Body)."')"); + +$PostID = $DB->inserted_id(); + +$DB->query("UPDATE forums SET + NumPosts = NumPosts+1, + NumTopics = NumTopics+1, + LastPostID = '$PostID', + LastPostAuthorID = '".$LoggedUser['ID']."', + LastPostTopicID = '$TopicID', + LastPostTime = '".sqltime()."' + WHERE ID = '$ForumID'"); + +$DB->query("UPDATE forums_topics SET + NumPosts = NumPosts+1, + LastPostID = '$PostID', + LastPostAuthorID = '".$LoggedUser['ID']."', + LastPostTime = '".sqltime()."' + WHERE ID = '$TopicID'"); + +if(isset($_POST['subscribe'])) { + $DB->query("INSERT INTO users_subscriptions VALUES ($LoggedUser[ID], $TopicID)"); + $Cache->delete_value('subscriptions_user_'.$LoggedUser['ID']); +} + +if (empty($_POST['question']) || empty($_POST['answers']) || !check_perms('forums_polls_create')) { + $NoPoll = 1; +} else { + $NoPoll = 0; + $Question = trim($_POST['question']); + $Answers = array(); + $Votes = array(); + + //This can cause polls to have answer ids of 1 3 4 if the second box is empty + foreach ($_POST['answers'] as $i => $Answer) { + if ($Answer == '') { continue; } + $Answers[$i+1] = $Answer; + $Votes[$i+1] = 0; + } + + if (count($Answers) < 2) { + error('You cannot create a poll with only one answer.'); + } else if(count($Answers) > 25) { + error('You cannot create a poll with greater than 25 answers'); + } + + $DB->query('INSERT INTO forums_polls (TopicID, Question, Answers) VALUES (\''.$TopicID.'\',\''.db_string($Question).'\',\''.db_string(serialize($Answers)).'\')'); + $Cache->cache_value('polls_'.$TopicID, array($Question,$Answers,$Votes,'0000-00-00 00:00:00','0'), 0); + + if($ForumID == STAFF_FORUM) { + send_irc("PRIVMSG ".ADMIN_CHAN." :!mod Poll created by ".$LoggedUser['Username'].": '".$Question."' http://".NONSSL_SITE_URL."/forums.php?action=viewthread&threadid=".$TopicID); + } +} + +//if cache exists modify it, if not, then it will be correct when selected next, and we can skip this block +if ($Forum = $Cache->get_value('forums_'.$ForumID)) { + list($Forum,,,$Stickies) = $Forum; + + //Remove the last thread from the index + if (count($Forum) == TOPICS_PER_PAGE && $Stickies < TOPICS_PER_PAGE) { + array_pop($Forum); + } + + if ($Stickies > 0) { + $Part1 = array_slice($Forum,0,$Stickies,true); //Stikys + $Part3 = array_slice($Forum,$Stickies,TOPICS_PER_PAGE-$Stickies-1,true); //Rest of page + } else { + $Part1 = array(); + $Part3 = $Forum; + } + $Part2 = array($TopicID => array( + 'ID' => $TopicID, + 'Title' => $Title, + 'AuthorID' => $LoggedUser['ID'], + 'AuthorUsername' => $LoggedUser['Username'], + 'IsLocked' => 0, + 'IsSticky' => 0, + 'NumPosts' => 1, + 'LastPostID' => $PostID, + 'LastPostTime' => sqltime(), + 'LastPostAuthorID' => $LoggedUser['ID'], + 'LastPostUsername' => $LoggedUser['Username'], + 'NoPoll' => $NoPoll + )); //Bumped + $Forum = $Part1 + $Part2 + $Part3; + + $Cache->cache_value('forums_'.$ForumID, array($Forum,'',0,$Stickies), 0); + + //Update the forum root + $Cache->begin_transaction('forums_list'); + $Cache->update_row($ForumID, array( + 'NumPosts'=>'+1', + 'NumTopics'=>'+1', + 'LastPostID'=>$PostID, + 'LastPostAuthorID'=>$LoggedUser['ID'], + 'Username'=>$LoggedUser['Username'], + 'LastPostTopicID'=>$TopicID, + 'LastPostTime'=>sqltime(), + 'Title'=>$Title, + 'IsLocked'=>0, + 'IsSticky'=>0 + )); + $Cache->commit_transaction(0); +} else { + //If there's no cache, we have no data, and if there's no data + $Cache->delete_value('forums_list'); +} + +$Cache->begin_transaction('thread_'.$TopicID.'_catalogue_0'); +$Post = array( + 'ID'=>$PostID, + 'AuthorID'=>$LoggedUser['ID'], + 'AddedTime'=>sqltime(), + 'Body'=>$Body, + 'EditedUserID'=>0, + 'EditedTime'=>'0000-00-00 00:00:00', + 'Username'=>'' + ); +$Cache->insert('', $Post); +$Cache->commit_transaction(0); + +$Cache->begin_transaction('thread_'.$TopicID.'_info'); +$Cache->update_row(false, array('Posts'=>'+1', 'LastPostAuthorID'=>$LoggedUser['ID'])); +$Cache->commit_transaction(0); + +header('Location: forums.php?action=viewthread&threadid='.$TopicID); +die(); diff --git a/sections/forums/take_reply.php b/sections/forums/take_reply.php new file mode 100644 index 00000000..25361f8f --- /dev/null +++ b/sections/forums/take_reply.php @@ -0,0 +1,229 @@ +query("INSERT IGNORE INTO users_subscriptions VALUES ($LoggedUser[ID], '".db_string($TopicID)."')"); + $Cache->delete_value('subscriptions_user_'.$LoggedUser['ID']); +} + +//Now lets handle the special case of merging posts, we can skip bumping the thread and all that fun +if ($ThreadInfo['LastPostAuthorID'] == $LoggedUser['ID'] && ((!check_perms('site_forums_double_post') && !in_array($ForumID, $ForumsDoublePost)) || isset($_POST['merge']))) { + //Get the id for this post in the database to append + $DB->query("SELECT ID FROM forums_posts WHERE TopicID='$TopicID' AND AuthorID='".$LoggedUser['ID']."' ORDER BY ID DESC LIMIT 1"); + list($PostID) = $DB->next_record(); + + //Edit the post + $DB->query("UPDATE forums_posts SET Body = CONCAT(Body,'"."\n\n".db_string($Body)."'), EditedUserID = '".$LoggedUser['ID']."', EditedTime = '".sqltime()."' WHERE ID='$PostID'"); + + //Get the catalogue it is in + $CatalogueID = floor((POSTS_PER_PAGE*ceil($ThreadInfo['Posts']/POSTS_PER_PAGE)-POSTS_PER_PAGE)/THREAD_CATALOGUE); + + //Get the catalogue value for the post we're appending to + if($ThreadInfo['Posts']%THREAD_CATALOGUE == 0) { + $Key = THREAD_CATALOGUE-1; + } else { + $Key = ($ThreadInfo['Posts']%THREAD_CATALOGUE)-1; + } + + //Edit the post in the cache + $Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID); + $Cache->update_row($Key, array( + 'Body'=>$Cache->MemcacheDBArray[$Key]['Body']."\n\n".$Body, + 'EditedUserID'=>$LoggedUser['ID'], + 'EditedTime'=>sqltime(), + 'Username'=>$LoggedUser['Username'] + )); + $Cache->commit_transaction(0); + +//Now we're dealing with a normal post +} else { + //Insert the post into the posts database + $DB->query("INSERT INTO forums_posts (TopicID, AuthorID, AddedTime, Body) + VALUES ('$TopicID', '".$LoggedUser['ID']."', '".sqltime()."', '".db_string($Body)."')"); + + $PostID = $DB->inserted_id(); + + //This updates the root index + $DB->query("UPDATE forums SET + NumPosts = NumPosts+1, + LastPostID = '$PostID', + LastPostAuthorID = '".$LoggedUser['ID']."', + LastPostTopicID = '$TopicID', + LastPostTime = '".sqltime()."' + WHERE ID = '$ForumID'"); + + //Update the topic + $DB->query("UPDATE forums_topics SET + NumPosts = NumPosts+1, + LastPostID = '$PostID', + LastPostAuthorID = '".$LoggedUser['ID']."', + LastPostTime = '".sqltime()."' + WHERE ID = '$TopicID'"); + + //if cache exists modify it, if not, then it will be correct when selected next, and we can skip this block + if ($Forum = $Cache->get_value('forums_'.$ForumID)) { + list($Forum,,,$Stickies) = $Forum; + + //if the topic is already on this page + if (array_key_exists($TopicID,$Forum)) { + $Thread = $Forum[$TopicID]; + unset($Forum[$TopicID]); + $Thread['NumPosts'] = $Thread['NumPosts']+1; //Increment post count + $Thread['LastPostID'] = $PostID; //Set postid for read/unread + $Thread['LastPostTime'] = sqltime(); //Time of last post + $Thread['LastPostAuthorID'] = $LoggedUser['ID']; //Last poster id + $Thread['LastPostUsername'] = $LoggedUser['Username']; //Last poster username + $Part2 = array($TopicID=>$Thread); //Bumped thread + + //if we're bumping from an older page + } else { + //Remove the last thread from the index + if (count($Forum) == TOPICS_PER_PAGE && $Stickies < TOPICS_PER_PAGE) { + array_pop($Forum); + } + //Never know if we get a page full of stickies... + if ($Stickies < TOPICS_PER_PAGE || $ThreadInfo['IsSticky'] == 1) { + //Pull the data for the thread we're bumping + $DB->query("SELECT f.AuthorID, f.IsLocked, f.IsSticky, f.NumPosts, u.Username, ISNULL(p.TopicID) AS NoPoll FROM forums_topics AS f INNER JOIN users_main AS u ON u.ID=f.AuthorID LEFT JOIN forums_polls AS p ON p.TopicID=f.ID WHERE f.ID ='$TopicID'"); + list($AuthorID,$IsLocked,$IsSticky,$NumPosts,$AuthorName,$NoPoll) = $DB->next_record(); + $Part2 = array($TopicID => array( + 'ID' => $TopicID, + 'Title' => $ThreadInfo['Title'], + 'AuthorID' => $AuthorID, + 'AuthorUsername' => $AuthorName, + 'IsLocked' => $IsLocked, + 'IsSticky' => $IsSticky, + 'NumPosts' => $NumPosts, + 'LastPostID' => $PostID, + 'LastPostTime' => sqltime(), + 'LastPostAuthorID' => $LoggedUser['ID'], + 'LastPostUsername' => $LoggedUser['Username'], + 'NoPoll' => $NoPoll + )); //Bumped + } else { + $Part2 = array(); + } + } + if ($Stickies > 0) { + $Part1 = array_slice($Forum,0,$Stickies,true); //Stickies + $Part3 = array_slice($Forum,$Stickies,TOPICS_PER_PAGE-$Stickies-1,true); //Rest of page + } else { + $Part1 = array(); + $Part3 = $Forum; + } + if (is_null($Part1)) { $Part1 = array(); } + if (is_null($Part3)) { $Part3 = array(); } + if($ThreadInfo['IsSticky'] == 1) { + $Forum = $Part2 + $Part1 + $Part3; //Merge it + } else { + $Forum = $Part1 + $Part2 + $Part3; //Merge it + } + $Cache->cache_value('forums_'.$ForumID, array($Forum,'',0,$Stickies), 0); + + //Update the forum root + $Cache->begin_transaction('forums_list'); + $Cache->update_row($ForumID, array( + 'NumPosts'=>'+1', + 'LastPostID'=>$PostID, + 'LastPostAuthorID'=>$LoggedUser['ID'], + 'Username'=>$LoggedUser['Username'], + 'LastPostTopicID'=>$TopicID, + 'LastPostTime'=>sqltime(), + 'Title'=>$ThreadInfo['Title'], + 'IsLocked'=>$ThreadInfo['IsLocked'], + 'IsSticky'=>$ThreadInfo['IsSticky'] + )); + $Cache->commit_transaction(0); + } else { + //If there's no cache, we have no data, and if there's no data + $Cache->delete_value('forums_list'); + } + + + //This calculates the block of 500 posts that this one will fall under + $CatalogueID = floor((POSTS_PER_PAGE*ceil($ThreadInfo['Posts']/POSTS_PER_PAGE)-POSTS_PER_PAGE)/THREAD_CATALOGUE); + + //Insert the post into the thread catalogue (block of 500 posts) + $Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID); + $Cache->insert('', array( + 'ID'=>$PostID, + 'AuthorID'=>$LoggedUser['ID'], + 'AddedTime'=>sqltime(), + 'Body'=>$Body, + 'EditedUserID'=>0, + 'EditedTime'=>'0000-00-00 00:00:00', + 'Username'=>$LoggedUser['Username'] //TODO: Remove, it's never used? + )); + $Cache->commit_transaction(0); + + //Update the thread info + $Cache->begin_transaction('thread_'.$TopicID.'_info'); + $Cache->update_row(false, array('Posts'=>'+1', 'LastPostAuthorID'=>$LoggedUser['ID'])); + $Cache->commit_transaction(0); + + //Increment this now to make sure we redirect to the correct page + $ThreadInfo['Posts']++; +} + +$DB->query("SELECT UserID FROM users_subscriptions WHERE TopicID = ".$TopicID); +if($DB->record_count() > 0) { + $Subscribers = $DB->collect('UserID'); + foreach($Subscribers as $Subscriber) { + $Cache->delete_value('subscriptions_user_new_'.$Subscriber); + } +} + +header('Location: forums.php?action=viewthread&threadid='.$TopicID.'&page='.ceil($ThreadInfo['Posts']/$PerPage)); +die(); diff --git a/sections/forums/takeedit.php b/sections/forums/takeedit.php new file mode 100644 index 00000000..a2ddcab6 --- /dev/null +++ b/sections/forums/takeedit.php @@ -0,0 +1,99 @@ +query("SELECT + p.Body, + p.AuthorID, + p.TopicID, + t.IsLocked, + t.ForumID, + f.MinClassWrite, + CEIL((SELECT COUNT(ID) + FROM forums_posts + WHERE forums_posts.TopicID = p.TopicID + AND forums_posts.ID <= '$PostID')/".POSTS_PER_PAGE.") + AS Page + FROM forums_posts as p + JOIN forums_topics as t on p.TopicID = t.ID + JOIN forums as f ON t.ForumID=f.ID + WHERE p.ID='$PostID'"); +list($OldBody, $AuthorID, $TopicID, $IsLocked, $ForumID, $MinClassWrite, $Page) = $DB->next_record(); + +// Make sure they aren't trying to edit posts they shouldn't +// We use die() here instead of error() because whatever we spit out is displayed to the user in the box where his forum post is +if(!check_forumperm($ForumID, 'Write') || ($IsLocked && !check_perms('site_moderate_forums'))) { + error('Either the thread is locked, or you lack the permission to edit this post.',true); +} +if($UserID != $AuthorID && !check_perms('site_moderate_forums')) { + error(403,true); +} +if($LoggedUser['DisablePosting']) { + error('Your posting rights have been removed.',true); +} +if($DB->record_count()==0) { + error(404,true); +} + +// Perform the update +$DB->query("UPDATE forums_posts SET + Body = '$Body', + EditedUserID = '$UserID', + EditedTime = '".sqltime()."' + WHERE ID='$PostID'"); + +$CatalogueID = floor((POSTS_PER_PAGE*$Page-POSTS_PER_PAGE)/THREAD_CATALOGUE); +$Cache->begin_transaction('thread_'.$TopicID.'_catalogue_'.$CatalogueID); +if ($Cache->MemcacheDBArray[$Key]['ID'] != $PostID) { + $Cache->cancel_transaction(); + $Cache->delete('thread_'.$TopicID.'_catalogue_'.$CatalogueID); //just clear the cache for would be cache-screwer-uppers +} else { + $Cache->update_row($Key, array( + 'ID'=>$Cache->MemcacheDBArray[$Key]['ID'], + 'AuthorID'=>$Cache->MemcacheDBArray[$Key]['AuthorID'], + 'AddedTime'=>$Cache->MemcacheDBArray[$Key]['AddedTime'], + 'Body'=>$_POST['body'], //Don't url decode. + 'EditedUserID'=>$LoggedUser['ID'], + 'EditedTime'=>sqltime(), + 'Username'=>$LoggedUser['Username'] + )); + $Cache->commit_transaction(3600*24*5); +} +//$Cache->delete('thread_'.$TopicID.'_page_'.$Page); // Delete thread cache + +$DB->query("INSERT INTO comments_edits (Page, PostID, EditUser, EditTime, Body) + VALUES ('forums', ".$PostID.", ".$UserID.", '".sqltime()."', '".db_string($OldBody)."')"); +$Cache->delete_value("forums_edits_$PostID"); +// This gets sent to the browser, which echoes it in place of the old body +echo $Text->full_format($_POST['body']); +?> +

    Last edited by just now diff --git a/sections/forums/thread.php b/sections/forums/thread.php new file mode 100644 index 00000000..cd41aef2 --- /dev/null +++ b/sections/forums/thread.php @@ -0,0 +1,588 @@ +query("SELECT TopicID FROM forums_posts WHERE ID = $_GET[postid]"); + list($ThreadID) = $DB->next_record(); + if($ThreadID) { + header("Location: forums.php?action=viewthread&threadid=$ThreadID&postid=$_GET[postid]#post$_GET[postid]"); + die(); + } else { + error(404); + } + } else { + error(404); + } +} else { + $ThreadID = $_GET['threadid']; +} + + + +if (isset($LoggedUser['PostsPerPage'])) { + $PerPage = $LoggedUser['PostsPerPage']; +} else { + $PerPage = POSTS_PER_PAGE; +} + +//---------- Get some data to start processing + +// Thread information, constant across all pages +$ThreadInfo = get_thread_info($ThreadID, true, true); +$ForumID = $ThreadInfo['ForumID']; + +// Make sure they're allowed to look at the page +if(!check_forumperm($ForumID)) { + error(403); +} + +//Post links utilize the catalogue & key params to prevent issues with custom posts per page +if($ThreadInfo['Posts'] > $PerPage) { + if(isset($_GET['post']) && is_number($_GET['post'])) { + $PostNum = $_GET['post']; + } elseif(isset($_GET['postid']) && is_number($_GET['postid'])) { + $DB->query("SELECT COUNT(ID) FROM forums_posts WHERE TopicID = $ThreadID AND ID <= $_GET[postid]"); + list($PostNum) = $DB->next_record(); + } else { + $PostNum = 1; + } +} else { + $PostNum = 1; +} +list($Page,$Limit) = page_limit($PerPage, min($ThreadInfo['Posts'],$PostNum)); +list($CatalogueID,$CatalogueLimit) = catalogue_limit($Page,$PerPage,THREAD_CATALOGUE); + +// Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page +if(!$Catalogue = $Cache->get_value('thread_'.$ThreadID.'_catalogue_'.$CatalogueID)) { + $DB->query("SELECT + p.ID, + p.AuthorID, + p.AddedTime, + p.Body, + p.EditedUserID, + p.EditedTime, + ed.Username + FROM forums_posts as p + LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID + WHERE p.TopicID = '$ThreadID' AND p.ID != '".$ThreadInfo['StickyPostID']."' + LIMIT $CatalogueLimit"); + $Catalogue = $DB->to_array(false,MYSQLI_ASSOC); + if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) { + $Cache->cache_value('thread_'.$ThreadID.'_catalogue_'.$CatalogueID, $Catalogue, 0); + } +} +$Thread = catalogue_select($Catalogue,$Page,$PerPage,THREAD_CATALOGUE); + +if ($_GET['updatelastread'] != '0') { + $LastPost = end($Thread); + $LastPost = $LastPost['ID']; + reset($Thread); + + //Handle last read + if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) { + $DB->query("SELECT PostID From forums_last_read_topics WHERE UserID='$LoggedUser[ID]' AND TopicID='$ThreadID'"); + list($LastRead) = $DB->next_record(); + if($LastRead < $LastPost) { + $DB->query("INSERT INTO forums_last_read_topics + (UserID, TopicID, PostID) VALUES + ('$LoggedUser[ID]', '".$ThreadID ."', '".db_string($LastPost)."') + ON DUPLICATE KEY UPDATE PostID='$LastPost'"); + } + } +} + +//Handle subscriptions +if(($UserSubscriptions = $Cache->get_value('subscriptions_user_'.$LoggedUser['ID'])) === FALSE) { + $DB->query("SELECT TopicID FROM users_subscriptions WHERE UserID = '$LoggedUser[ID]'"); + $UserSubscriptions = $DB->collect(0); + $Cache->cache_value('subscriptions_user_'.$LoggedUser['ID'],$UserSubscriptions,0); +} + +if(empty($UserSubscriptions)) { + $UserSubscriptions = array(); +} + +if(in_array($ThreadID, $UserSubscriptions)) { + $Cache->delete_value('subscriptions_user_new_'.$LoggedUser['ID']); +} + +// Start printing +show_header('Forums'.' > '.$Forums[$ForumID]['Name'].' > '.$ThreadInfo['Title'],'comments,subscriptions,bbcode'); +?> +
    +

    + Forums > + > + +

    + +get_value('polls_'.$ThreadID)) { + $DB->query("SELECT Question, Answers, Featured, Closed FROM forums_polls WHERE TopicID='".$ThreadID."'"); + list($Question, $Answers, $Featured, $Closed) = $DB->next_record(MYSQLI_NUM, array(1)); + $Answers = unserialize($Answers); + $DB->query("SELECT Vote, COUNT(UserID) FROM forums_polls_votes WHERE TopicID='$ThreadID' GROUP BY Vote"); + $VoteArray = $DB->to_array(false, MYSQLI_NUM); + + $Votes = array(); + foreach ($VoteArray as $VoteSet) { + list($Key,$Value) = $VoteSet; + $Votes[$Key] = $Value; + } + + foreach(array_keys($Answers) as $i) { + if (!isset($Votes[$i])) { + $Votes[$i] = 0; + } + } + $Cache->cache_value('polls_'.$ThreadID, array($Question,$Answers,$Votes,$Featured,$Closed), 0); + } + + if (!empty($Votes)) { + $TotalVotes = array_sum($Votes); + $MaxVotes = max($Votes); + } else { + $TotalVotes = 0; + $MaxVotes = 0; + } + + $RevealVoters = in_array($ForumID, $ForumsRevealVoters); + //Polls lose the you voted arrow thingy + $DB->query("SELECT Vote FROM forums_polls_votes WHERE UserID='".$LoggedUser['ID']."' AND TopicID='$ThreadID'"); + list($UserResponse) = $DB->next_record(); + if (!empty($UserResponse) && $UserResponse != 0) { + $Answers[$UserResponse] = '» '.$Answers[$UserResponse]; + } else { + if(!empty($UserResponse) && $RevealVoters) { + $Answers[$UserResponse] = '» '.$Answers[$UserResponse]; + } + } + +?> +
    +
    Poll (View)
    +
    +

    + +
      + $Answer) { + if (!empty($Votes[$i]) && $TotalVotes > 0) { + $Ratio = $Votes[$i]/$MaxVotes; + $Percent = $Votes[$i]/$TotalVotes; + } else { + $Ratio=0; + $Percent=0; + } +?> +
    • (%)
    • +
    • + + + +
    • + 0) { +?> +
    • (Blank) (%)
    • +
    • + + + +
    • + +
    +
    + Votes:

    +query("SELECT fpv.Vote AS Vote, + GROUP_CONCAT(um.Username SEPARATOR ', ') + FROM users_main AS um + LEFT JOIN forums_polls_votes AS fpv ON um.ID = fpv.UserID + WHERE TopicID = ".$ThreadID." + GROUP BY fpv.Vote"); + + $StaffVotesTmp = $DB->to_array(); + $StaffCount = count($StaffNames); + + $StaffVotes = array(); + foreach($StaffVotesTmp as $StaffVote) { + list($Vote, $Names) = $StaffVote; + $StaffVotes[$Vote] = $Names; + $Names = explode(", ", $Names); + $StaffNames = array_diff($StaffNames, $Names); + } +?>
      + $Answer) { +?> +
    • + + -  (%) + [X] +
    • + +
    • Blank -  (%)
    • +
    + +
    + Votes: / +
    + Missing Votes: +

    + + [+] + +
    +
    + + + + +
      + $Answer) { //for ($i = 1, $il = count($Answers); $i <= $il; $i++) { ?> +
    • + + +
    • + +
    • +
      +
      +
    • +
    + + [+] +
    +
    + + +
    +
    + + + +
    + + + + + +
    + +
    + + + + + +
    + +
    +
    + $Post){ + list($PostID, $AuthorID, $AddedTime, $Body, $EditedUserID, $EditedTime, $EditedUsername) = array_values($Post); + list($AuthorID, $Username, $PermissionID, $Paranoia, $Artist, $Donor, $Warned, $Avatar, $Enabled, $UserTitle) = array_values(user_info($AuthorID)); + + // Image proxy CTs + if(check_perms('site_proxy_images') && !empty($UserTitle)) { + $UserTitle = preg_replace_callback('~src=("?)(http.+?)(["\s>])~', function($Matches) { + return 'src='.$Matches[1].'http'.($SSL?'s':'').'://'.SITE_URL.'/image.php?c=1&i='.urlencode($Matches[2]).$Matches[3]; + }, $UserTitle); + } +?> + + + + + + + + + + +
    + # + + + + + - [Quote] + + - [Edit] + 1) { ?> + - [Delete] + + [Sticky] + + - [X] + + - [⇕] + + + + [Report] +   + + +
    + + <?=$Username ?>'s avatar + + Default avatar + + > +
    + full_format($Body) ?> + +
    +
    + + « + + Last edited by + + +
    +
    + + + + +
    +

    Post reply

    +
    + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + tabindex="2" /> + + + + + + + +
    +
    +
    + +
    +

    Edit thread

    +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Sticky + tabindex="2" /> +
    Locked + tabindex="2" /> +
    Title + +
    Move thread + +
    Delete thread + +
    + +
    +
    + +
    +query("INSERT IGNORE INTO friends (UserID, FriendID) VALUES ('$LoggedUser[ID]', '$FriendID')"); +header('Location: friends.php'); +?> \ No newline at end of file diff --git a/sections/friends/comment.php b/sections/friends/comment.php new file mode 100644 index 00000000..ce1d7ccd --- /dev/null +++ b/sections/friends/comment.php @@ -0,0 +1,4 @@ +query("UPDATE friends SET Comment='$P[comment]' WHERE UserID='$LoggedUser[ID]' AND FriendID='$P[friendid]'"); +header('Location: friends.php'); +?> \ No newline at end of file diff --git a/sections/friends/friends.php b/sections/friends/friends.php new file mode 100644 index 00000000..27b55430 --- /dev/null +++ b/sections/friends/friends.php @@ -0,0 +1,133 @@ + query("SELECT + SQL_CALC_FOUND_ROWS + f.FriendID, + f.Comment, + m.Username, + m.Uploaded, + m.Downloaded, + m.PermissionID, + m.Enabled, + m.Paranoia, + i.Donor, + i.Warned, + m.Title, + m.LastAccess, + i.Avatar + FROM friends AS f + JOIN users_main AS m ON f.FriendID=m.ID + JOIN users_info AS i ON f.FriendID=i.UserID + WHERE f.UserID='$UserID' + ORDER BY Username LIMIT $Limit"); +$Friends = $DB->to_array(false, MYSQLI_BOTH, array(7)); + +// Number of results (for pagination) +$DB->query('SELECT FOUND_ROWS()'); +list($Results) = $DB->next_record(); + +// Start printing stuff +?> +
    +

    Friends list

    + +
    +You have no friends! :(

    '; +} +// Start printing out friends +foreach($Friends as $Friend) { + list($FriendID, $Comment, $Username, $Uploaded, $Downloaded, $Class, $Enabled, $Paranoia, $Donor, $Warned, $Title, $LastAccess, $Avatar) = $Friend; +?> +
    + + + + + + + + + + +
    + + +  Ratio: + + +  Up: + + +  Down: + + + + + +
    + + <?=$Username?>'s avatar + + Default avatar + + + + + + +
    +
    +
    + +
    +
    + +?> +
    + + ?> +
    + diff --git a/sections/friends/index.php b/sections/friends/index.php new file mode 100644 index 00000000..72c323c2 --- /dev/null +++ b/sections/friends/index.php @@ -0,0 +1,33 @@ + diff --git a/sections/friends/remove.php b/sections/friends/remove.php new file mode 100644 index 00000000..f5cc827c --- /dev/null +++ b/sections/friends/remove.php @@ -0,0 +1,4 @@ +query("DELETE FROM friends WHERE UserID='$LoggedUser[ID]' AND FriendID='$P[friendid]'"); +header('Location: friends.php'); +?> \ No newline at end of file diff --git a/sections/image/badprotocol.gif b/sections/image/badprotocol.gif new file mode 100644 index 0000000000000000000000000000000000000000..b4a2735ac8e6ff61dc16237b142ead56582c1fc9 GIT binary patch literal 904 zcmV;319$vKNk%w1VUPi20J9GO0001ph=?L0B4%c0-QC?pL`0dHnY+8Y%*@O)Gcyqp z5$^8pRaI4YcXz6)s{jB0A^8LW000jFEC2ui0FVJ>000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!o$SH#>dFX%FE2nzXkvk z1p`(B0T=-Q+5!hW1=`fkRM67lLIDCG*4XI}1qurw00t}5;^Wa0_Cx6E*BAXB5CG8a z!@PRt?m;1^kD7o10stsLpif(Zcj{h&c?3dchOc)jnklgtkP4R9O)WdYIJNykJDwBb~8165B5 zDB-8J1KB3@wjFb&`n3P>OGth`+I9*96%-)lERhd8uB(PcoxFsOoPSb_- zQe6QohgW*O)z_VG`Gk~ThZS%*0dW&V_ds$Q#^ziFDlS)DflHir4Q&cG_YVUOGEl%| zbJfO{N)}Eg07i>lW8ws#QFIN45;QZr?<%4d0~GNY=6t;Q#exvs_U-2 z_Uh}ezy>Squ*4Q??6JrutL(DOHtXy)v(QE>?X=WZYwfkzW~=SC+;;2jx8Q~=?zrTZ eYwo$|rmOC{?6&LfyYR*<@4WQZYp<*k0028)EW1Sj literal 0 HcmV?d00001 diff --git a/sections/image/forbidden.gif b/sections/image/forbidden.gif new file mode 100644 index 0000000000000000000000000000000000000000..bcabf3d0cc9a9d0557455ad25393e3cb58aea0df GIT binary patch literal 728 zcmV;}0w?`PNk%w1VUPi20J9GO0001)nVE=)h~3@Y5fKqYL_}3pRlB>pcXxL)Gc(N0 z%w}e0s;a6YA|meY?*IS)A^8LW000jFEC2ui0FVJ>000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!o$SH#>dFXstN!MJ_P{L z1r8w#03QL@%8Cd82+s=-3Ju{g+1rW<4GG{9+0-!S=!Xsf2LK8a0R+(k5(){Vx#O2$ zfCK^28svL$fFFPW848peVDG^`00k`qKnNfl#b^fqCv*c)K%YZx^9nH_@F0P|2Mjho zaNutMfszmW-Gf-bfVgHk%Mti?ph3iP51Q?K&{N~XYzwo6%t=7OfCf5c%1cQIflsdz z68NNmfF%V3V^_{3X>ehJ1P8<&l~9iXS_x{iL8KU0<5U7K!QR!#wGd#KX0cXSfOA5F zXpkiwfR+H_g8|kKV~{9;;yB3B2w$$~w=-yx4>WHr42T(MXJRXqtzh6A1_J=#9RzxT zvqb_9YFCiQ*ByYr&M0Vx##)d7b`pfgv|N)wIh_RJ4)_*e0X2jU1{BE0EV%{F?507gZZ zkUyUdg!EFvck3j5OA0get_value('image_cache_'.md5($URL)); + $Cached = true; +} +if(!isset($Data) || !$Data) { + $Cached = false; + $Data = @file_get_contents($URL,0,stream_context_create(array('http'=>array('timeout'=>15)))); + if(!$Data || empty($Data)) { + error('timeout'); + } + $Type = image_type($Data); + if($Type && function_exists('imagecreatefrom'.$Type)) { + $Image = imagecreatefromstring($Data); + if(invisible($Image)) { + error('invisible'); + } + if(verysmall($Image)) { + error('small'); + } + } + + if(isset($_GET['c']) && strlen($Data) < 262144) { + $Cache->cache_value('image_cache_'.md5($URL), array($Data,$Type), 3600*24*7); + } +} + +// Enforce avatar rules +if(isset($_GET['avatar'])) { + if(!is_number($_GET['avatar'])) { die(); } + $UserID = $_GET['avatar']; + + $Height = image_height($Type, $Data); + if(strlen($Data)>256*1024 || $Height>400) { + // Sometimes the cached image we have isn't the actual image + if($Cached) { + $Data2 = @file_get_contents($URL,0,stream_context_create(array('http'=>array('timeout'=>15)))); + } else { + $Data2 = $Data; + } + if(strlen($Data2)>256*1024 || image_height($Type, $Data2)>400) { + require_once(SERVER_ROOT.'/classes/class_mysql.php'); + require_once(SERVER_ROOT.'/classes/class_time.php'); //Require the time class + + $DB = new DB_MYSQL; + $DBURL = db_string($URL); + + // Reset avatar, add mod note + $UserInfo = $Cache->get_value('user_info_'.$UserID); + $UserInfo['Avatar'] = ''; + $Cache->cache_value('user_info_'.$UserID, $UserInfo, 2592000); + + $DB->query("UPDATE users_info SET Avatar='', AdminComment=CONCAT('".sqltime()." - Avatar reset automatically (Size: ".number_format((strlen($Data))/1024)."kb, Height: ".$Height."px). Used to be $DBURL\n\n', AdminComment) WHERE UserID='$UserID'"); + + // Send PM + + send_pm($UserID,0,"Your avatar has been automatically reset","The following avatar rules have been in effect for months now: + +[b]Avatars must not exceed 256kB or be vertically longer than 400px. [/b] + +Your avatar at $DBURL has been found to exceed these rules. As such, it has been automatically reset. You are welcome to reinstate your avatar once it has been resized down to an acceptable size."); + + + } + } +} + +/* +TODO: solve this properl for photoshop output images which prepend shit to the image file. skip it or strip it +if (!isset($Type)) { + error('timeout'); +} +*/ +if(isset($Type)) { + header('Content-type: image/'.$Type); +} +echo $Data; +?> diff --git a/sections/image/invalid.gif b/sections/image/invalid.gif new file mode 100644 index 0000000000000000000000000000000000000000..c3aef4804f9106288a8f37cccdc272165a9ee568 GIT binary patch literal 843 zcmV-R1GM}{Nk%w1VUPi20J9GO0000YA|l=0-DYNHL_|c0h=`e)nY+8YGcz+05fRMH z%000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!o$SH#>dFXjsgJ9%?2g} z%>xw!02l)V7zNG&2g<0--zfyt9@*Og5(EhgH3t9!;C|vNY%5-3m*Z$bcQ+?w%wa8ClWW&tHMaHdTkKX~r{4j{z%;Gi@B<`_5|U;x0z0@4&b zFpvNMf`9-iEI3&}LQ87^_?<-HPT&}V2#E$@K(Xh81MM6DfH<+@gq9f#B>0xk!oCLz z5HJ;xfLcy#3JpGJ5I|?B1(-P8xBxdaKM78m0KPdU9do02@VoS$SHxL%*Z`kLK7_2 z-0j0)kZ$gnzyULvs0UZI>=QG?ahxeoo>1}Z#HX0w#zPlipR;DOG0*%CAh&o41rPur z@Ef=n;S%z}gef68f#nsj)&}rRK!A>3T}RRQWTIV{lYcC2r%iW{SwI_D02FmuMidBu z00Qm>$Dc#PSrn9EVo?+nbOi1g90SVuAv2N7q*UK=we5 zPwmwaT_#e{fKv=$m?0MzIRj01@d3!r1PUOeSyj_qHsW|TF#up^0xqClc?IUzjAS_K zIG8g&t{Id(7M}Tyepij;&60TLspp=2_UY%JfCeh)poA7`=%I)vs_3GOHtOi3kVY!$ zq?A@_>7|%vs_CYjcIxS;poS{ysHB!^>Zz!vs_Lq&w(9Duu*NFuthCl@>#exvs_U-2 V_Uh}ezy>Squ*4Q?EHM!P06U(VB0|5a80cX$7)s{jB0A^8LW000jFEC2ui0FVJ>000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!ma}d000L&1qlxU49x*2 z1;{W0$H&ni0t6h>$r1$F69m{I*4N_0DFXln4+h^k4hRnk0uKxWOal5g;TQi#@Ke_U zLBAdf04y-JAi=>T1O25NH}OM6f+-FFP+)-px@H9b$hDKe?%2Ht+s+jTz)eDdlNA;K zaB%DZ0tXLD0yvrSSOEh7N+wu<(&q%0BHcYGVC>k02GllOMCvo4fe8W%OxsDprqQA! z!7)fslOhELWD&%}5OEsR0pvIyI0xV=+H1)chJa;5z|80|X8?D$d#XaXX*@0s!p?RB5xqhZ6@~3gBr}4O3AgelS^rO`^?UK0wgm z!Q2U@$L%!0fF3w;3!@d2+HV>Ik4y&`KoCu%f$7|UCL=IZBS&C<7x+Rc6GT*%e zAa_L3Bws)|87EVP^EHReZ2SObTV2apctAqmITVa{UDb6QNG`P&mU<{n6dzm}kP|>j z58TL8I@rXX zOAqQc0XsNZXj(ui(k9LT%y>X1mfW0~UR`SDgiJ!Xsl$#t@W>>cHFiQ;&okr{dSzi6 zK;?i;+$4Z2S2^x_=zpf&>6e7GIVA!ARBN&IXp|OaMS+z^62MVHnI`(rGzW3GP(KaG zCvA*wdY`5+9+i=G%_uO>XZTH=H=dJhNeE045-+%`$_~3*WZusGdC$9M7 zj5qH1a4f!`s=XAE;}X> G00294rx%$3 literal 0 HcmV?d00001 diff --git a/sections/image/nogd.gif b/sections/image/nogd.gif new file mode 100644 index 0000000000000000000000000000000000000000..79929bfe57c04e70800a52fafefe4a15bab878c0 GIT binary patch literal 945 zcmV;i15W%$Nk%w1VUPi20J9GO0001)nVE=)h$12)W@ctYL`1v0yAcr)-QC?)RaMN) z%ri4H?(Xh)cXz6)s{jB0A^8LW000jFEC2ui0FVJ>000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!o$SH#>dFX%FE2nwE_nK z01gk*(hV5_)&K-I0|iFb0VV?i9NNx40s!L-2G!%*;}_^1>{j<2`6T7%0O>srn4^%7 zzyb{Q^v$EPPeVfy{Wc^7h{FH?1r_p5q_A-vf(H)&27H89p@B4T4+s<}AZ;E?01FsA z&<0=t1p@=54IDrq=K+itRKA?IuI4)l4>2@MAZ@`&oYp=vcnM&jNdPEkMw3QSM?IF~ z@>!H=fu^*h3u69!P*fb-p9uO90PvH*fwvzEEbKV}LDiW6-sOxrAOVKCb?<6>XO}_S zmJaudWUv4nf&<+w=5_j@A2bDV%~>?Ju`7*)1H#U80Dx?T(w7AiT=+otg9e6sVnoNf z+XJ8}ZAySPA%WomF;ix(pd0W5;}dKry|B-=f{P7=YrYP&pKaXF4Ldh|!(w;U5(3<% z_s@dKqevI}-3Cr&`t|}AU2iueEmX-&}ITg4qW(16ULgbs8PNJm=+ z)eXcQgu?-Vz=RKsR@;iv4aCxhH>@*`hxcg1?X=WZYwfkzW~=SC+;;2jx8Q~=?zrTZ zYwo$|rmOC{?6&LfyYR*<@4WQZYwx}I=Bw|%{PyebzW@g;@W2EYZ1BMdC#>+o3^(lX T!w^R-@x&BYZ1KgIL;wIgquj=& literal 0 HcmV?d00001 diff --git a/sections/image/small.gif b/sections/image/small.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bcd94a3e4f4b9307ea658faaae25df9687f88be GIT binary patch literal 1167 zcmV;A1aSLDNk%w1VUPi20J9GO{{R60W@i5)BL9ep|J~jHnVJ7YME?;H|GT^YGc*70 z?*Gip|5a80cX$7)s{jB0A^8LW000jFEC2ui0FVJ>000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!ma}c000O(1qlxU49x*2 z1;{T0%n}L!3oQx;$J8F)0MQZy#{wGx-vH>tB<2MV1j#xM2M-D83dd~clz!YDSxn?`SIh(;$@Yz8xbUcAUus@e;e$Edq$D&(g$LD2=pZ^J z1ywdEL79f;$E7zRECdb%4ODy3eJ_765E@4)AlC8SI=SK53|D^ zkPHE#j!NB+8Y}=(st$ol8HWRWw7@*IEQgXV=dJhNeE045-+%`$_~3*WZusGdC$9M7 zj5qH1a4f!`s=XAF8l1X h*KYgmxaY3>?!5Qz`|rR9FZ}St7jOLW$U_nV06T|yHW2^- literal 0 HcmV?d00001 diff --git a/sections/image/timeout.gif b/sections/image/timeout.gif new file mode 100644 index 0000000000000000000000000000000000000000..f79c74582f51e4417c9bc28ba1db259043ced77f GIT binary patch literal 1099 zcmV-R1ho4{Nk%w1VUPi20J9GO0001ph=?L0BAJ<)5fKsH-QBypyJlu)L_|bYRaMN) z%000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v z&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!m(*V^c1J?ir!#V&14+aDQG|J2m(H`&8-5~KGP=7x4`GLZ0ve!TSmN8i9RU$Y{C0qvgapO^7>GkqtwA;c`UD=hV9?#Ofe4D3 zb7$RDIw<41Iix}?lRDe(BftLabEMSnW0D%Su1VBv+)#%#^Eu(cLpx^+3 z2V%`d+h$-IU6&LBFfM>H?zLy%m^p?@)ZAUD2JRt1rg@~f&;kjNj%T=8w$$cUYvB4o zKsj!jA2bj^7r{!g>MR;v860i~V+`7TGyUx70|fx+ie)@Oz-xyO662+7k%8IC+!q9_ zXT1TkpYsyDe_-9hwafA)ICw19EZzJPSXa;g0cM5u0D$}L=1*4$C=dj=_1G?4a z&SMX#cbRkc%{0L`T7|ca1T8Tj+lS8}kWvNW2}F=Z>)F&zjEI5blLhs3*42s>l#@?a z;55S)0(9xvn?Chmw?I-rUZY@l2e1=bI8CjT6H@-*WXxe4N)XV8R8C+Wc60^6fL9bm z1ORCksONwL1G$Lh0~yIEL28$=_a+DR07xH?6R1XI0ur&r00RfkCm=s6s`yc%9PlPU zl*>#h4rf;C6O%iLcB#RaScWK2UVCMu009MHm(n-$UBK6M1eo@sKMWuflbs5nc~E9d zRhEHRW!5FyiKU6S5<1KjAW;MQB!DRRY@_W;!2rH#g=~0`ULYx@20)k-X8^2pD1~Vm zrB4H*dP=88jfTwYCiBG7hJ*>q-LV zoZ9isFr*goESjy%^Uy>WZS>JdC$03-OgHWH(@;k(_0&{XZS~byXRY*wdY`5+9+i=G%_uO>XZTH=H=dJhNeE045-+%`$_~3*WZusGdC$9M7 Rj5qH1query("SELECT Username FROM users_main WHERE ID='$ToID'"); +list($Username) = $DB->next_record(); +if(!$Username) { error(404); } +show_header('Compose', 'inbox,bbcode'); +?> +
    +

    Send a message to

    +
    +
    + + + +
    +

    Subject

    +
    +

    Body

    + +
    + +
    + + +
    +
    +
    +
    + + diff --git a/sections/inbox/conversation.php b/sections/inbox/conversation.php new file mode 100644 index 00000000..06c116f8 --- /dev/null +++ b/sections/inbox/conversation.php @@ -0,0 +1,172 @@ +query("SELECT InInbox, InSentbox FROM pm_conversations_users WHERE UserID='$UserID' AND ConvID='$ConvID'"); +if($DB->record_count() == 0) { + error(403); +} +list($InInbox, $InSentbox) = $DB->next_record(); + + + + +if (!$InInbox && !$InSentbox) { + + error(404); +} + +// Get information on the conversation +$DB->query("SELECT + c.Subject, + cu.Sticky, + cu.UnRead, + cu.ForwardedTo, + um.Username + FROM pm_conversations AS c + JOIN pm_conversations_users AS cu ON c.ID=cu.ConvID + LEFT JOIN users_main AS um ON um.ID=cu.ForwardedTo + WHERE c.ID='$ConvID' AND UserID='$UserID'"); +list($Subject, $Sticky, $UnRead, $ForwardedID, $ForwardedName) = $DB->next_record(); + +$DB->query("SELECT UserID, Username, PermissionID, Enabled, Donor, Warned + FROM pm_messages AS pm + JOIN users_info AS ui ON ui.UserID=pm.SenderID + JOIN users_main AS um ON um.ID=pm.SenderID + WHERE pm.ConvID='$ConvID'"); + +while(list($PMUserID, $Username, $PermissionID, $Enabled, $Donor, $Warned) = $DB->next_record()) { + $PMUserID = (int)$PMUserID; + $Users[$PMUserID]['UserStr'] = format_username($PMUserID, $Username, $Donor, $Warned, $Enabled == 2 ? false : true, $PermissionID); + $Users[$PMUserID]['Username'] = $Username; +} +$Users[0]['UserStr'] = 'System'; // in case it's a message from the system +$Users[0]['Username'] = 'System'; + + + +if($UnRead=='1') { + + $DB->query("UPDATE pm_conversations_users SET UnRead='0' WHERE ConvID='$ConvID' AND UserID='$UserID'"); + // Clear the caches of the inbox and sentbox + $Cache->decrement('inbox_new_'.$UserID); +} + +show_header('View conversation '.$Subject, 'comments,inbox,bbcode'); + +// Get messages +$DB->query("SELECT SentDate, SenderID, Body, ID FROM pm_messages AS m WHERE ConvID='$ConvID' ORDER BY ID"); +?> +
    +

    0 ? ' (Forwarded to '.$ForwardedName.')':'')?>

    + +next_record()) { ?> +
    +
    + - [Quote] +
    +
    + full_format($Body)?> +
    +
    +query("SELECT UserID FROM pm_conversations_users WHERE UserID!='$LoggedUser[ID]' AND ConvID='$ConvID' AND (ForwardedTo=0 OR ForwardedTo=UserID)"); +$ReceiverIDs = $DB->collect('UserID'); + + +if(!empty($ReceiverIDs) && (empty($LoggedUser['DisablePM']) || array_intersect($ReceiverIDs, array_keys($StaffIDs)))) { +?> +

    Reply

    +
    +
    + + + + +
    + +
    + + +
    +
    +
    + +

    Manage conversation

    +
    +
    + + + + + + + + + + + + + + + + + +
    + /> + + + + +
    +
    +
    +query("SELECT SupportFor FROM users_info WHERE UserID = ".$LoggedUser['ID']); +list($FLS) = $DB->next_record(); +if((check_perms('users_mod') || $FLS != "") && (!$ForwardedID || $ForwardedID == $LoggedUser['ID'])) { +?> +

    Forward conversation

    +
    +
    + + + + + + +
    +
    + +
    + diff --git a/sections/inbox/forward.php b/sections/inbox/forward.php new file mode 100644 index 00000000..abc96525 --- /dev/null +++ b/sections/inbox/forward.php @@ -0,0 +1,26 @@ +query("SELECT ConvID FROM pm_conversations_users WHERE UserID='$UserID' AND InInbox='1' AND (ForwardedTo=0 OR ForwardedTo=UserID) AND ConvID='$ConvID'"); +if($DB->record_count() == 0) { error(403); } + +$DB->query("SELECT ConvID FROM pm_conversations_users WHERE UserID='$ReceiverID' AND (ForwardedTo = 0 OR ForwardedTo = UserID) AND InInbox='1' AND ConvID='$ConvID'"); +if($DB->record_count() == 0) { + $DB->query("INSERT IGNORE INTO pm_conversations_users + (UserID, ConvID, InInbox, InSentbox, ReceivedDate) + VALUES ('$ReceiverID', '$ConvID', '1', '0', NOW()) + ON DUPLICATE KEY UPDATE ForwardedTo = 0, UnRead = 1"); + $DB->query("UPDATE pm_conversations_users SET ForwardedTo='$ReceiverID' WHERE ConvID='$ConvID' AND UserID='$UserID'"); + $Cache->delete_value('inbox_new_'.$ReceiverID); + header('Location: inbox.php'); +} else { + error("$StaffIDs[$ReceiverID] already has this conversation in their inbox."); + header('Location: inbox.php?action=viewconv&id='.$ConvID); +} +//show_footer(); +?> diff --git a/sections/inbox/get_post.php b/sections/inbox/get_post.php new file mode 100644 index 00000000..2f74b74f --- /dev/null +++ b/sections/inbox/get_post.php @@ -0,0 +1,35 @@ +query("SELECT + m.Body + FROM pm_messages as m + JOIN pm_conversations_users AS u ON m.ConvID=u.ConvID + WHERE m.ID='$PostID' + AND u.UserID=".$LoggedUser['ID']); +list($Body) = $DB->next_record(MYSQLI_NUM); + +// This gets sent to the browser, which echoes it wherever + +echo trim($Body); + +?> \ No newline at end of file diff --git a/sections/inbox/inbox.php b/sections/inbox/inbox.php new file mode 100644 index 00000000..ee7e42bb --- /dev/null +++ b/sections/inbox/inbox.php @@ -0,0 +1,169 @@ + +
    +

    + + +
    +record_count()==0) { ?> +

    Your is currently empty

    + + +
    + + + + + + + + + + + + +next_record()) { + if($Unread === '1') { + $RowClass = 'unreadpm'; + } else { + $Row = ($Row === 'a') ? 'b' : 'a'; + $RowClass = 'row'.$Row; + } +?> + + + + + + + + + + +
    SubjectDateForwarded to
    +'; } ?> + + +';} ?> +
    +   +   + +
    + +
    + +
    + diff --git a/sections/inbox/index.php b/sections/inbox/index.php new file mode 100644 index 00000000..8c6f4b90 --- /dev/null +++ b/sections/inbox/index.php @@ -0,0 +1,42 @@ +get_value("staff_ids"); +if(!is_array($StaffIDs)) { + $DB->query("SELECT m.ID, m.Username + FROM users_main AS m + JOIN permissions AS p ON p.ID=m.PermissionID + WHERE p.DisplayStaff='1'"); + while(list($StaffID, $StaffName) = $DB->next_record()) { + $StaffIDs[$StaffID] = $StaffName; + } + uasort($StaffIDs, 'strcasecmp'); + $Cache->cache_value("staff_ids", $StaffIDs); +} + +if(!isset($_REQUEST['action'])) { $_REQUEST['action'] = ''; } +switch($_REQUEST['action']) { + case 'takecompose': + require('takecompose.php'); + break; + case 'takeedit': + require('takeedit.php'); + break; + case 'compose': + require('compose.php'); + break; + case 'viewconv': + require('conversation.php'); + break; + case 'masschange': + require('massdelete_handle.php'); + break; + case 'get_post': + require('get_post.php'); + break; + case 'forward': + require('forward.php'); + break; + default: + require(SERVER_ROOT.'/sections/inbox/inbox.php'); +} diff --git a/sections/inbox/massdelete_handle.php b/sections/inbox/massdelete_handle.php new file mode 100644 index 00000000..1430dff4 --- /dev/null +++ b/sections/inbox/massdelete_handle.php @@ -0,0 +1,45 @@ +query("SELECT COUNT(ConvID) FROM pm_conversations_users WHERE ConvID IN ($ConvIDs) AND UserID=$UserID"); +list($MessageCount) = $DB->next_record(); +if($MessageCount != count($Messages)){ + error(0); +} + +if (isset($_POST['delete'])) { + $DB->query("UPDATE pm_conversations_users SET + InInbox='0', + InSentbox='0', + Sticky='0', + UnRead='0' + WHERE ConvID IN($ConvIDs) AND UserID=$UserID"); +} elseif (isset($_POST['unread'])) { + $DB->query("UPDATE pm_conversations_users SET Unread='1' + WHERE ConvID IN($ConvIDs) AND UserID=$UserID"); +} elseif (isset($_POST['read'])) { + $DB->query("UPDATE pm_conversations_users SET Unread='0' + WHERE ConvID IN($ConvIDs) AND UserID=$UserID"); +} +$Cache->delete_value('inbox_new_'.$UserID); + +header('Location: inbox.php'); +?> diff --git a/sections/inbox/takecompose.php b/sections/inbox/takecompose.php new file mode 100644 index 00000000..aadb7986 --- /dev/null +++ b/sections/inbox/takecompose.php @@ -0,0 +1,54 @@ +query("SELECT UserID FROM pm_conversations_users WHERE UserID='$LoggedUser[ID]' AND ConvID='$ConvID'"); + if($DB->record_count() == 0) { + error(403); + } +} else { + $ConvID=''; + if(!is_number($_POST['toid'])) { + $Err = "This recipient does not exist."; + } else { + $ToID = $_POST['toid']; + } + $Subject = trim($_POST['subject']); + if (empty($Subject)) { + $Err = "You can't send a message without a subject."; + } +} +$Body = trim($_POST['body']); +if(empty($Body)) { + $Err = "You can't send a message without a body!"; +} + +if(!empty($Err)) { + error($Err); + //header('Location: inbox.php?action=compose&to='.$_POST['toid']); + $ToID = $_POST['toid']; + $Return = true; + include(SERVER_ROOT.'/sections/inbox/compose.php'); + die(); +} + +$ConvID = send_pm($ToID,$LoggedUser['ID'],db_string($Subject),db_string($Body),$ConvID); + +header('Location: inbox.php'); +?> diff --git a/sections/inbox/takeedit.php b/sections/inbox/takeedit.php new file mode 100644 index 00000000..939ceb94 --- /dev/null +++ b/sections/inbox/takeedit.php @@ -0,0 +1,34 @@ +query("SELECT UserID FROM pm_conversations_users WHERE UserID='$UserID' AND ConvID='$ConvID'"); +if($DB->record_count() == 0) { error(403); } + +if(isset($_POST['delete'])) { + $DB->query("UPDATE pm_conversations_users SET + InInbox='0', + InSentbox='0', + Sticky='0' + WHERE ConvID='$ConvID' AND UserID='$UserID'"); +} else { + if(isset($_POST['sticky'])) { + $DB->query("UPDATE pm_conversations_users SET + Sticky='1' + WHERE ConvID='$ConvID' AND UserID='$UserID'"); + } else { + $DB->query("UPDATE pm_conversations_users SET + Sticky='0' + WHERE ConvID='$ConvID' AND UserID='$UserID'"); + } + if(isset($_POST['mark_unread'])) { + $DB->query("UPDATE pm_conversations_users SET + Unread='1' + WHERE ConvID='$ConvID' AND UserID='$UserID'"); + $Cache->increment('inbox_new_'.$UserID); + } +} +header('Location: inbox.php'); +?> diff --git a/sections/index/index.php b/sections/index/index.php new file mode 100644 index 00000000..02cb374a --- /dev/null +++ b/sections/index/index.php @@ -0,0 +1,17 @@ + diff --git a/sections/index/private.php b/sections/index/private.php new file mode 100644 index 00000000..d6788eff --- /dev/null +++ b/sections/index/private.php @@ -0,0 +1,478 @@ +get_value('news')) { + $DB->query("SELECT + ID, + Title, + Body, + Time + FROM news + ORDER BY Time DESC + LIMIT 5"); + $News = $DB->to_array(false,MYSQLI_NUM,false); + $Cache->cache_value('news',$News,3600*24*30); + $Cache->cache_value('news_latest_id', $News[0][0], 0); +} + +if ($LoggedUser['LastReadNews'] != $News[0][0]) { + $Cache->begin_transaction('user_info_heavy_'.$UserID); + $Cache->update_row(false, array('LastReadNews' => $News[0][0])); + $Cache->commit_transaction(0); + $DB->query("UPDATE users_info SET LastReadNews = '".$News[0][0]."' WHERE UserID = ".$UserID); + $LoggedUser['LastReadNews'] = $News[0][0]; +} + +show_header('News','bbcode'); +?> +
    + +
    +get_value('recommend'); +$Recommend_artists = $Cache->get_value('recommend_artists'); + +if (!is_array($Recommend) || !is_array($Recommend_artists)) { + $DB->query("SELECT + tr.GroupID, + tr.UserID, + u.Username, + tg.Name, + tg.TagList + FROM torrents_recommended AS tr + JOIN torrents_group AS tg ON tg.ID=tr.GroupID + LEFT JOIN users_main AS u ON u.ID=tr.UserID + ORDER BY tr.Time DESC LIMIT 10 + "); + $Recommend = $DB->to_array(); + $Cache->cache_value('recommend',$Recommend,1209600); + + $Recommend_artists = get_artists($DB->collect('GroupID')); + $Cache->cache_value('recommend_artists',$Recommend_artists,1209600); +} + +if (count($Recommend) >= 4) { +$Cache->increment('usage_index'); +?> + + + time()) { + continue; + } +?> +
    +
    + full_format($Title)?> + + - [Edit] + +
    +
    full_format($Body)?>
    +
    + 4) { + break; + } +} +?> +
    +
    + For older news posts, click here +
    +
    +
    +
    +true)); + +function contest() { + global $DB, $Cache, $LoggedUser; + + list($Contest, $TotalPoints) = $Cache->get_value('contest'); + if(!$Contest) { + $DB->query("SELECT + UserID, + SUM(Points), + Username + FROM users_points AS up + JOIN users_main AS um ON um.ID=up.UserID + GROUP BY UserID + ORDER BY SUM(Points) DESC + LIMIT 20"); + $Contest = $DB->to_array(); + + $DB->query("SELECT SUM(Points) FROM users_points"); + list($TotalPoints) = $DB->next_record(); + + $Cache->cache_value('contest', array($Contest,$TotalPoints), 600); + } + +?> + +
    +
    Quality time scoreboard
    +
    +
      + +
    1. ()
    2. + +
    + Total uploads:
    + Full scoreboard +
    +
    + + diff --git a/sections/index/public.php b/sections/index/public.php new file mode 100644 index 00000000..94451d12 --- /dev/null +++ b/sections/index/public.php @@ -0,0 +1,4 @@ + +
    You've stumbled upon a door where your mind is the key. There are none who will lend you guidance; these trials are yours to conquer alone. Entering here will take more than mere logic and strategy, but the criteria are just as hidden as what they reveal. Find yourself, and you will find the very thing hidden behind this page. Beyond here is something like a utopia - beyond here is What.CD.
    +This is a mirage. + diff --git a/sections/irc/index.php b/sections/irc/index.php new file mode 100644 index 00000000..e69de29b diff --git a/sections/log/index.php b/sections/log/index.php new file mode 100644 index 00000000..493db7cb --- /dev/null +++ b/sections/log/index.php @@ -0,0 +1,231 @@ +'".time_minus(3600*24*28)."' "; +} + +$sql .= "ORDER BY ID DESC LIMIT $Limit"; + +show_header("Site log"); + +$Log = $DB->query($sql); +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); +$DB->set_query_id($Log); +?> +
    +

    Site log

    +
    +
    + + + + + +
    Search for: + /> +   + +
    +
    +
    + + + + + + + + + + + +record_count() == 0) { + echo ''; +} +$Row = 'a'; +$Usernames = array(); +while(list($Message, $LogTime) = $DB->next_record()) { + $MessageParts = explode(" ", $Message); + $Message = ""; + $Color = $Colon = false; + for ($i = 0, $PartCount = sizeof($MessageParts); $i < $PartCount; $i++) { + if ((strpos($MessageParts[$i], 'https://'.SSL_SITE_URL) === 0 && $Offset = strlen('https://'.SSL_SITE_URL.'/')) || + (strpos($MessageParts[$i], 'http://'.NONSSL_SITE_URL) === 0 && $Offset = strlen('http://'.NONSSL_SITE_URL.'/'))) { + $MessageParts[$i] = ''.substr($MessageParts[$i], $Offset).''; + } + switch ($MessageParts[$i]) { + case "Torrent": + case "torrent": + $TorrentID = $MessageParts[$i + 1]; + if (is_numeric($TorrentID)) { + $Message = $Message.' '.$MessageParts[$i].' '.$TorrentID.''; + $i++; + } else { + $Message = $Message.' '.$MessageParts[$i]; + } + break; + case "Request": + $RequestID = $MessageParts[$i + 1]; + if (is_numeric($RequestID)) { + $Message = $Message.' '.$MessageParts[$i].' '.$RequestID.''; + $i++; + } else { + $Message = $Message.' '.$MessageParts[$i]; + } + break; + case "Artist": + case "artist": + $ArtistID = $MessageParts[$i + 1]; + if (is_numeric($ArtistID)) { + $Message = $Message.' '.$MessageParts[$i].' '.$ArtistID.''; + $i++; + } else { + $Message = $Message.' '.$MessageParts[$i]; + } + break; + case "group": + case "Group": + $GroupID = $MessageParts[$i + 1]; + if (is_numeric($GroupID)) { + $Message = $Message.' '.$MessageParts[$i].' '.$GroupID.''; + } else { + $Message = $Message.' '.$MessageParts[$i]; + } + $i++; + break; + case "by": + $UserID = 0; + $User = ""; + $URL = ""; + if ($MessageParts[$i + 1] == "user") { + $i++; + if (is_numeric($MessageParts[$i + 1])) { + $UserID = $MessageParts[++$i]; + } + $URL = "user ".$UserID." ".''.$MessageParts[++$i].""; + } else { + $User = $MessageParts[++$i]; + if(substr($User,-1) == ':') { + $User = substr($User, 0, -1); + $Colon = true; + } + if(!isset($Usernames[$User])) { + $DB->query("SELECT ID FROM users_main WHERE Username = '".$User."'"); + list($UserID) = $DB->next_record(); + $Usernames[$User] = $UserID ? $UserID : ''; + } else { + $UserID = $Usernames[$User]; + } + $DB->set_query_id($Log); + $URL = $Usernames[$User] ? ''.$User."".($Colon?':':'') : $User; + } + $Message = $Message." by ".$URL; + break; + case "uploaded": + if ($Color === false) { + $Color = 'green'; + } + $Message = $Message." ".$MessageParts[$i]; + break; + case "deleted": + if ($Color === false || $Color === 'green') { + $Color = 'red'; + } + $Message = $Message." ".$MessageParts[$i]; + break; + case "edited": + if ($Color === false) { + $Color = 'blue'; + } + $Message = $Message." ".$MessageParts[$i]; + break; + case "un-filled": + if ($Color === false) { + $Color = ''; + } + $Message = $Message." ".$MessageParts[$i]; + break; + case "marked": + if ($i == 1) { + $User = $MessageParts[$i - 1]; + if(!isset($Usernames[$User])) { + $DB->query("SELECT ID FROM users_main WHERE Username = '".$User."'"); + list($UserID) = $DB->next_record(); + $Usernames[$User] = $UserID ? $UserID : ''; + $DB->set_query_id($Log); + } else { + $UserID = $Usernames[$User]; + } + $URL = $Usernames[$User] ? ''.$User."" : $User; + $Message = $URL." ".$MessageParts[$i]; + } else { + $Message = $Message.' '.$MessageParts[$i]; + } + break; + case "Collage": + $CollageID = $MessageParts[$i + 1]; + if (is_numeric($CollageID)) { + $Message = $Message.' '.$MessageParts[$i].' '.$CollageID.''; + $i++; + } else { + $Message = $Message.' '.$MessageParts[$i]; + } + break; + default: + $Message = $Message." ".$MessageParts[$i]; + } + } + $Row = ($Row == 'a') ? 'b' : 'a'; +?> + + + + + +
    TimeMessage
    Nothing found!
    + + + style="color: ;"> +
    + +
    + diff --git a/sections/login/disabled.php b/sections/login/disabled.php new file mode 100644 index 00000000..f313b714 --- /dev/null +++ b/sections/login/disabled.php @@ -0,0 +1,61 @@ + +

    +Your account has been disabled.
    +This is either due to inactivity or rule violation.
    +To discuss this come to our IRC at:
    +And join

    +Be honest - at this point, lying will get you nowhere.

    +

    +

    +If you do not have access to an IRC client you can use the WebIRC interface provided below.
    +Please use your What.CD? username. +

    +
    +
    + + +
    + + +
    +

    Disabled IRC

    +
    +
    +

    Please read the topic carefully.

    +
    +
    + + + + + + + + + + + + + + +
    +
    +
    + diff --git a/sections/login/index.php b/sections/login/index.php new file mode 100644 index 00000000..1727bc42 --- /dev/null +++ b/sections/login/index.php @@ -0,0 +1,322 @@ +query("SELECT + m.ID, + m.Email, + i.ResetExpires + FROM users_main AS m + INNER JOIN users_info AS i ON i.UserID=m.ID + WHERE i.ResetKey='".db_string($_REQUEST['key'])."' + AND i.ResetKey<>'' + AND m.Enabled='1'"); + list($UserID,$Email,$Expires)=$DB->next_record(); + + if ($UserID && strtotime($Expires)>time()) { + // If the user has requested a password change, and his key has not expired + $Validate->SetFields('password','1','string','You entered an invalid password.',array('maxlength'=>'40','minlength'=>'6')); + $Validate->SetFields('verifypassword','1','compare','Your passwords did not match.',array('comparefield'=>'password')); + + if (!empty($_REQUEST['password'])) { + // If the user has entered a password. + // If the user has not entered a password, $Reset is not set to 1, and the success message is not shown + $Err=$Validate->ValidateForm($_REQUEST); + if ($Err=='') { + // Form validates without error, set new secret and password. + $Secret=make_secret(); + $DB->query("UPDATE + users_main AS m, + users_info AS i + SET m.PassHash='".db_string(make_hash($_REQUEST['password'],$Secret))."', + m.Secret='".db_string($Secret)."', + i.ResetKey='', + i.ResetExpires='0000-00-00 00:00:00' + WHERE m.ID='".db_string($UserID)."' + AND i.UserID=m.ID"); + $Reset = true; // Past tense form of "to reset", meaning that password has now been reset + } + } + + // Either a form asking for them to enter the password + // Or a success message if $Reset is 1 + require('recover_step2.php'); + + } else { + // Either his key has expired, or he hasn't requested a pass change at all + + if (strtotime($Expires)query("UPDATE + users_info + SET ResetKey='', + ResetExpires='0000-00-00 00:00:00' + WHERE UserID='$UserID'"); + $_SESSION['reseterr']="The link you were given has expired."; // Error message to display on form + } + // Show him the first form (enter email address) + header('Location: login.php?act=recover'); + } + + } // End step 2 + + // User has not clicked the link in his email, use step 1 + else { + $Validate->SetFields('email','1','email','You entered an invalid email address.'); + + if (!empty($_REQUEST['email'])) { + // User has entered email and submitted form + $Err=$Validate->ValidateForm($_REQUEST); + + if (!$Err) { + // Form validates correctly + $DB->query("SELECT + ID, + Username, + Email + FROM users_main + WHERE Email='".db_string($_REQUEST['email'])."' + AND Enabled='1'"); + list($UserID,$Username,$Email)=$DB->next_record(); + + if ($UserID) { + // Email exists in the database + // Set ResetKey, send out email, and set $Sent to 1 to show success page + $ResetKey=make_secret(); + $DB->query("UPDATE users_info SET + ResetKey='".db_string($ResetKey)."', + ResetExpires='".time_plus(60*60)."' + WHERE UserID='$UserID'"); + + require(SERVER_ROOT.'/classes/class_templates.php'); + $TPL=NEW TEMPLATE; + $TPL->open(SERVER_ROOT.'/templates/password_reset.tpl'); // Password reset template + + $TPL->set('Username',$Username); + $TPL->set('ResetKey',$ResetKey); + $TPL->set('IP',$_SERVER['REMOTE_ADDR']); + $TPL->set('SITE_NAME',SITE_NAME); + $TPL->set('SITE_URL',NONSSL_SITE_URL); + + send_email($Email,'Password reset information for '.SITE_NAME,$TPL->get(),'noreply'); + $Sent=1; // If $Sent is 1, recover_step1.php displays a success message + + //Log out all of the users current sessions + $Cache->delete_value('user_info_'.$UserID); + $Cache->delete_value('user_info_heavy_'.$UserID); + $Cache->delete_value('user_stats_'.$UserID); + $Cache->delete_value('enabled_'.$UserID); + + $DB->query("SELECT SessionID FROM users_sessions WHERE UserID='$UserID'"); + while(list($SessionID) = $DB->next_record()) { + $Cache->delete_value('session_'.$UserID.'_'.$SessionID); + } + $DB->query("UPDATE users_sessions SET Active = 0 WHERE UserID='$UserID' AND Active = 1"); + + + } else { + $Err="There is no user with that email address."; + } + } + + } elseif (!empty($_SESSION['reseterr'])) { + // User has not entered email address, and there is an error set in session data + // This is typically because their key has expired. + // Stick the error into $Err so recover_step1.php can take care of it + $Err=$_SESSION['reseterr']; + unset($_SESSION['reseterr']); + } + + // Either a form for the user's email address, or a success message + require('recover_step1.php'); + } // End if (step 1) + +} // End password recovery + +// Normal login +else { + $Validate->SetFields('username',true,'regex','You did not enter a valid username.',array('regex'=>'/^[a-z0-9_?]{1,20}$/i')); + $Validate->SetFields('password','1','string','You entered an invalid password.',array('maxlength'=>'40','minlength'=>'6')); + + $DB->query("SELECT ID, Attempts, Bans, BannedUntil FROM login_attempts WHERE IP='".db_string($_SERVER['REMOTE_ADDR'])."'"); + list($AttemptID,$Attempts,$Bans,$BannedUntil)=$DB->next_record(); + + // Function to log a user's login attempt + function log_attempt($UserID) { + global $DB, $AttemptID, $Attempts, $Bans, $BannedUntil, $Time; + if($AttemptID) { // User has attempted to log in recently + $Attempts++; + if ($Attempts>5) { // Only 6 allowed login attempts, ban user's IP + $BannedUntil=time_plus(60*60*6); + $DB->query("UPDATE login_attempts SET + LastAttempt='".sqltime()."', + Attempts='".db_string($Attempts)."', + BannedUntil='".db_string($BannedUntil)."', + Bans=Bans+1 + WHERE ID='".db_string($AttemptID)."'"); + + if ($Bans>9) { // Automated bruteforce prevention + $IP = ip2unsigned($_SERVER['REMOTE_ADDR']); + $DB->query("SELECT Reason FROM ip_bans WHERE ".$IP." BETWEEN FromIP AND ToIP"); + if($DB->record_count() > 0) { + //Ban exists already, only add new entry if not for same reason + list($Reason) = $DB->next_record(MYSQLI_BOTH, false); + if($Reason != "Automated ban per >60 failed login attempts") { + $DB->query("UPDATE ip_bans + SET Reason = CONCAT('Automated ban per >60 failed login attempts AND ', Reason) + WHERE FromIP = ".$IP." AND ToIP = ".$IP); + } + } else { + //No ban + $DB->query("INSERT INTO ip_bans + (FromIP, ToIP, Reason) VALUES + ('$IP','$IP', 'Automated ban per >60 failed login attempts')"); + $Cache->delete_value('ip_bans'); + } + } + } else { + // User has attempted fewer than 6 logins + $DB->query("UPDATE login_attempts SET + LastAttempt='".sqltime()."', + Attempts='".db_string($Attempts)."', + BannedUntil='0000-00-00 00:00:00' + WHERE ID='".db_string($AttemptID)."'"); + } + } else { // User has not attempted to log in recently + $Attempts=1; + $DB->query("INSERT INTO login_attempts + (UserID,IP,LastAttempt,Attempts) VALUES + ('".db_string($UserID)."','".db_string($_SERVER['REMOTE_ADDR'])."','".sqltime()."',1)"); + } + } // end log_attempt function + + // If user has submitted form + if(isset($_POST['username']) && !empty($_POST['username']) && isset($_POST['password']) && !empty($_POST['password'])) { + $Err=$Validate->ValidateForm($_POST); + + if(!$Err) { + // Passes preliminary validation (username and password "look right") + $DB->query("SELECT + ID, + PermissionID, + CustomPermissions, + PassHash, + Secret, + Enabled + FROM users_main WHERE Username='".db_string($_POST['username'])."' + AND Username<>''"); + list($UserID,$PermissionID,$CustomPermissions,$PassHash,$Secret,$Enabled)=$DB->next_record(MYSQLI_NUM, array(2)); + if (strtotime($BannedUntil)encrypt($Enc->encrypt($SessionID.'|~|'.$UserID)); + + if(isset($_POST['keeplogged']) && $_POST['keeplogged']) { + $KeepLogged = 1; + setcookie('session', $Cookie,time()+60*60*24*365,'/','',false); + } else { + $KeepLogged = 0; + setcookie('session', $Cookie,0,'/','',false); + } + + //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that + // Because we <3 our staff + $Permissions = get_permissions($PermissionID); + $CustomPermissions = unserialize($CustomPermissions); + if ( + isset($Permissions['Permissions']['site_disable_ip_history']) || + isset($CustomPermissions['site_disable_ip_history']) + ) { $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; } + + + + $DB->query("INSERT INTO users_sessions + (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate) + VALUES ('$UserID', '".db_string($SessionID)."', '$KeepLogged', '$Browser','$OperatingSystem', '".db_string($_SERVER['REMOTE_ADDR'])."', '".sqltime()."')"); + + $Cache->begin_transaction('users_sessions_'.$UserID); + $Cache->insert_front($SessionID,array( + 'SessionID'=>$SessionID, + 'Browser'=>$Browser, + 'OperatingSystem'=>$OperatingSystem, + 'IP'=>$_SERVER['REMOTE_ADDR'], + 'LastUpdate'=>sqltime() + )); + $Cache->commit_transaction(0); + + $Sql = "UPDATE users_main + SET + LastLogin='".sqltime()."', + LastAccess='".sqltime()."'"; + + $Sql .= " WHERE ID='".db_string($UserID)."'"; + + $DB->query($Sql); + + if (!empty($_COOKIE['redirect'])) { + $URL = $_COOKIE['redirect']; + setcookie('redirect','',time()-60*60*24,'/','',false); + header('Location: '.$URL); + die(); + } else { + header('Location: index.php'); + die(); + } + } else { + log_attempt($UserID); + if ($Enabled==2) { + + header('location:login.php?action=disabled'); + } elseif ($Enabled==0) { + $Err="Your account has not been confirmed.
    Please check your email."; + } + setcookie('keeplogged','',time()+60*60*24*365,'/','',false); + } + } else { + log_attempt($UserID); + + $Err="Your username or password was incorrect."; + setcookie('keeplogged','',time()+60*60*24*365,'/','',false); + } + + } else { + log_attempt($UserID); + setcookie('keeplogged','',time()+60*60*24*365,'/','',false); + } + + } else { + log_attempt('0'); + setcookie('keeplogged','',time()+60*60*24*365,'/','',false); + } + } + require("sections/login/login.php"); +} diff --git a/sections/login/login.php b/sections/login/login.php new file mode 100644 index 00000000..0e4ce020 --- /dev/null +++ b/sections/login/login.php @@ -0,0 +1,65 @@ + + + + +
    +query("UPDATE login_attempts SET BannedUntil='0000-00-00 00:00:00', Attempts='0' WHERE ID='".db_string($AttemptID)."'"); + $Attempts = 0; + } + if(isset($Err)) { +?> +

    + + 0) { ?> + You have attempts remaining.

    + WARNING: You will be banned for 6 hours after your login attempts run out!

    + + + + + + + + + + + + + + + +
    Username 
    Password 
    + checked="checked" /> + +
    +
    + + Your IP is banned indefinitely. + + You are banned from logging in for another . + 0) { +?> +

    + Lost your password? Recover it here! + + + diff --git a/sections/login/recover_step1.php b/sections/login/recover_step1.php new file mode 100644 index 00000000..1858116d --- /dev/null +++ b/sections/login/recover_step1.php @@ -0,0 +1,31 @@ +GenerateJS('recoverform'); +?> +
    +
    + Reset your password - Step 1

    + +

    + + An email will be sent to your email address with information on how to reset your password

    + + + + + + + + +
    Email 
    + + An email has been sent to you, please follow the directions in that email to reset your password. + +
    +
    + diff --git a/sections/login/recover_step2.php b/sections/login/recover_step2.php new file mode 100644 index 00000000..be587d64 --- /dev/null +++ b/sections/login/recover_step2.php @@ -0,0 +1,37 @@ +GenerateJS('recoverform'); +?> +
    + +
    + Reset your password - Final Step

    + +

    + + Please choose a password between 6 and 15 characters long

    + + + + + + + + + + + + +
    Password 
    Confirm Password 
    + + Your password has been succesfully reset.
    + Please click here to log in using your new password. + +
    +
    + diff --git a/sections/logout/index.php b/sections/logout/index.php new file mode 100644 index 00000000..56f895c1 --- /dev/null +++ b/sections/logout/index.php @@ -0,0 +1,4 @@ +'; +} + +ignore_user_abort(); +ini_set('max_execution_time',600); +ini_set('memory_limit','4096M'); +ob_end_flush(); +gc_enable(); + + +$DB->query("TRUNCATE TABLE torrents_peerlists_compare"); +$DB->query("INSERT INTO torrents_peerlists_compare (GroupID, SeedersList, LeechersList, SnatchedList) + SELECT GroupID, + GROUP_CONCAT(CONCAT(ID,'.',Seeders) ORDER BY ID SEPARATOR '|'), + GROUP_CONCAT(CONCAT(ID,'.',Leechers) ORDER BY ID SEPARATOR '|'), + GROUP_CONCAT(CONCAT(ID,'.',Snatched) ORDER BY ID SEPARATOR '|') + FROM torrents GROUP BY GroupID; +"); + +$DB->query("select t1.GroupID,t2.SeedersList,t2.LeechersList,t2.SnatchedList FROM torrents_peerlists AS t1 JOIN torrents_peerlists_compare AS t2 ON t1.GroupID=t2.GroupID WHERE t1.SeedersList!=t2.SeedersList OR t1.LeechersList!=t2.LeechersList OR t1.SnatchedList!=t2.SnatchedList ORDER BY t1.GroupID"); + +while(list($GroupID,$Seeders,$Leechers,$Snatched) = $DB->next_record(MYSQLI_NUM)) { + $Data = $Cache->get_value('torrent_group_'.$GroupID); + if (!(is_array($Data) && (@$Data['ver'] >= 4))) { continue; } + $Data = $Data['d']; + + $Changed = false; + + $Seeders = explode('|',$Seeders); + $Leechers = explode('|',$Leechers); + $Snatched = explode('|',$Snatched); + + $TotalSeeders = 0; + $TotalLeechers = 0; + $TotalSnatched = 0; + + foreach($Seeders as $Nums) { + list($TorrentID, $Val) = explode('.',$Nums); + if(is_array($Data['Torrents']) && isset($Data['Torrents'][$TorrentID]) && is_array($Data['Torrents'][$TorrentID])) { + if($Data['Torrents'][$TorrentID]['Seeders']!=$Val) { + $Data['Torrents'][$TorrentID]['Seeders']=$Val; + $Changed = true; + } + } + $TotalSeeders+=$Val; + } + foreach($Leechers as $Nums) { + list($TorrentID, $Val) = explode('.',$Nums); + if(is_array($Data['Torrents']) && isset($Data['Torrents'][$TorrentID]) && is_array($Data['Torrents'][$TorrentID])) { + if($Data['Torrents'][$TorrentID]['Leechers']!=$Val) { + $Data['Torrents'][$TorrentID]['Leechers']=$Val; + $Changed = true; + } + } + $TotalLeechers+=$Val; + } + foreach($Snatched as $Nums) { + list($TorrentID, $Val) = explode('.',$Nums); + if(is_array($Data['Torrents']) && isset($Data['Torrents'][$TorrentID]) && is_array($Data['Torrents'][$TorrentID])) { + if($Data['Torrents'][$TorrentID]['Snatched']!=$Val) { + $Data['Torrents'][$TorrentID]['Snatched']=$Val; + $Changed = true; + } + } + $TotalSnatched=$Val; + } + if($Changed) { + $Cache->cache_value('torrent_group_'.$GroupID, array('ver'=>4,'d'=>$Data), 0); + } + unset($Data); +} + +$DB->query("TRUNCATE TABLE torrents_peerlists"); +$DB->query("INSERT INTO torrents_peerlists + (GroupID, SeedersList, LeechersList, SnatchedList) + SELECT GroupID, SeedersList, LeechersList, SnatchedList FROM torrents_peerlists_compare"); + + +echo microtime(true)-$ScriptStartTime; +if (check_perms('admin_schedule')) { + echo '

    7-7tD9#f*i&wzqaP@=u{c^y7`P--H2GM#M< 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 M_<>dL>xbU{Up8SGOaK4? literal 0 HcmV?d00001 diff --git a/classes/fonts/GEORGIAB.TTF b/classes/fonts/GEORGIAB.TTF new file mode 100644 index 0000000000000000000000000000000000000000..a0c25f34aead7c00dd0c789d110c9e49e2cf9550 GIT binary patch literal 60268 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

    ';
    +	show_footer();
    +}
    +?>
    diff --git a/sections/register/closed.php b/sections/register/closed.php
    new file mode 100644
    index 00000000..aca9bc7c
    --- /dev/null
    +++ b/sections/register/closed.php
    @@ -0,0 +1,9 @@
    +
    +
    + Sorry, the site is currently invite only. +
    + diff --git a/sections/register/code.php b/sections/register/code.php new file mode 100644 index 00000000..29e530b6 --- /dev/null +++ b/sections/register/code.php @@ -0,0 +1,20 @@ + +
    +
    + Please enter your invite code into the box bellow.

    + + + + + + + + +
    Invite 
    +
    +
    + diff --git a/sections/register/index.php b/sections/register/index.php new file mode 100644 index 00000000..f5008a50 --- /dev/null +++ b/sections/register/index.php @@ -0,0 +1,212 @@ +query("SELECT ID FROM users_main WHERE torrent_pass='".db_string($_REQUEST['confirm'])."' AND Enabled='0'"); + list($UserID)=$DB->next_record(); + + if($UserID) { + $DB->query("UPDATE users_main SET Enabled='1' WHERE ID='$UserID'"); + $Cache->increment('stats_user_count'); + include('step2.php'); + } + +} elseif(OPEN_REGISTRATION || !empty($_REQUEST['invite'])) { + $Val->SetFields('username',true,'regex', 'You did not enter a valid username.',array('regex'=>'/^[a-z0-9_?]{1,20}$/iD')); + $Val->SetFields('email',true,'email', 'You did not enter a valid email address.'); + $Val->SetFields('password',true,'string', 'You did not enter a valid password (6 - 40 characters).',array('minlength'=>6,'maxlength'=>40)); + $Val->SetFields('confirm_password',true,'compare', 'Your passwords do not match.',array('comparefield'=>'password')); + $Val->SetFields('readrules',true,'checkbox', 'You did not check the box that says you will read the rules.'); + $Val->SetFields('readwiki',true,'checkbox', 'You did not check the box that says you will read the wiki.'); + $Val->SetFields('agereq',true,'checkbox', 'You did not check the box that says you are 13 or older.'); + //$Val->SetFields('captcha',true,'string', 'You did not enter a captcha code.',array('minlength'=>6,'maxlength'=>6)); + + if(!empty($_POST['submit'])) { + // User has submitted registration form + $Err=$Val->ValidateForm($_REQUEST); + /* + if(!$Err && strtolower($_SESSION['captcha'])!=strtolower($_REQUEST['captcha'])) { + $Err="You did not enter the correct captcha code."; + } + */ + if(!$Err) { + + $DB->query("SELECT COUNT(ID) FROM users_main WHERE Username LIKE '".db_string(trim($_POST['username']))."'"); + list($UserCount)=$DB->next_record(); + + if($UserCount) { + $Err = "There is already someone registered with that username."; + $_REQUEST['username']=''; + } + + if($_POST['invite']) { + $DB->query("SELECT InviterID, Email FROM invites WHERE InviteKey='".db_string($_REQUEST['invite'])."'"); + if($DB->record_count() == 0) { + $Err = 'Invite does not exist.'; + $InviterID=0; + } else { + list($InviterID, $InviteEmail) = $DB->next_record(); + } + } else { + $InviterID=0; + } + } + + if(!$Err) { + $Secret=make_secret(); + $torrent_pass=make_secret(); + + //Previously SELECT COUNT(ID) FROM users_main, which is a lot slower. + $DB->query("SELECT ID FROM users_main LIMIT 1"); + $UserCount = $DB->record_count(); + if($UserCount == 0) { + $NewInstall = true; + $Class = SYSOP; + $Enabled = '1'; + } else { + $NewInstall = false; + $Class = USER; + $Enabled = '0'; + } + + $ipcc = geoip($_SERVER['REMOTE_ADDR']); + + + $DB->query("INSERT INTO users_main + (Username,Email,PassHash,Secret,torrent_pass,IP,PermissionID,Enabled,Invites,Uploaded,ipcc) VALUES + ('".db_string(trim($_POST['username']))."','".db_string($_POST['email'])."','".db_string(make_hash($_POST['password'],$Secret))."','".db_string($Secret)."','".db_string($torrent_pass)."','".db_string($_SERVER['REMOTE_ADDR'])."','".$Class."','".$Enabled."','".STARTING_INVITES."', '524288000', '$ipcc')"); + + $UserID = $DB->inserted_id(); + + + //User created, delete invite. If things break after this point then it's better to have a broken account to fix, or a 'free' invite floating around that can be reused + $DB->query("DELETE FROM invites WHERE InviteKey='".db_string($_REQUEST['invite'])."'"); + + $DB->query("SELECT ID FROM stylesheets WHERE `Default`='1'"); + list($StyleID) = $DB->next_record(); + $AuthKey = make_secret(); + + $DB->query("INSERT INTO users_info (UserID,StyleID,AuthKey, Inviter, JoinDate) VALUES ('$UserID','$StyleID','".db_string($AuthKey)."', '$InviterID', '".sqltime()."')"); + + $DB->query("INSERT INTO users_history_ips + (UserID, IP, StartTime) VALUES + ('$UserID', '".db_string($_SERVER['REMOTE_ADDR'])."', '".sqltime()."')"); + + + + + $DB->query("INSERT INTO users_history_emails + (UserID, Email, Time, IP) VALUES + ('$UserID', '".db_string($_REQUEST['email'])."', '0000-00-00 00:00:00', '".db_string($_SERVER['REMOTE_ADDR'])."')"); + + if ($_REQUEST['email'] != $InviteEmail) { + $DB->query("INSERT INTO users_history_emails + (UserID, Email, Time, IP) VALUES + ('$UserID', '$InviteEmail', '".sqltime()."', '".db_string($_SERVER['REMOTE_ADDR'])."')"); + } + + + + // Manage invite trees, delete invite + + if($InviterID !== NULL) { + $DB->query("SELECT + TreePosition, TreeID, TreeLevel + FROM invite_tree WHERE UserID='$InviterID'"); + list($InviterTreePosition, $TreeID, $TreeLevel) = $DB->next_record(); + + // If the inviter doesn't have an invite tree + // Note - this should never happen unless you've transfered from another db, like we have + if($DB->record_count() == 0) { + $DB->query("SELECT MAX(TreeID)+1 FROM invite_tree"); + list($TreeID) = $DB->next_record(); + + $DB->query("INSERT INTO invite_tree + (UserID, InviterID, TreePosition, TreeID, TreeLevel) + VALUES ('$InviterID', '0', '1', '$TreeID', '1')"); + + $TreePosition = 2; + $TreeLevel = 2; + } else { + $DB->query("SELECT + TreePosition + FROM invite_tree + WHERE TreePosition>'$InviterTreePosition' + AND TreeLevel<='$TreeLevel' + AND TreeID='$TreeID' + ORDER BY TreePosition + LIMIT 1"); + list($TreePosition) = $DB->next_record(); + + if($TreePosition) { + $DB->query("UPDATE invite_tree SET TreePosition=TreePosition+1 WHERE TreeID='$TreeID' AND TreePosition>='$TreePosition'"); + } else { + $DB->query("SELECT + TreePosition+1 + FROM invite_tree + WHERE TreeID='$TreeID' + ORDER BY TreePosition DESC + LIMIT 1"); + list($TreePosition) = $DB->next_record(); + } + $TreeLevel++; + + // Create invite tree record + $DB->query("INSERT INTO invite_tree + (UserID, InviterID, TreePosition, TreeID, TreeLevel) VALUES + ('$UserID', '$InviterID', '$TreePosition', '$TreeID', '$TreeLevel')"); + } + } else { // No inviter (open registration) + $DB->query("SELECT MAX(TreeID) FROM invite_tree"); + list($TreeID) = $DB->next_record(); + $TreeID++; + $InviterID = 0; + $TreePosition=1; + $TreeLevel=1; + } + + + include(SERVER_ROOT.'/classes/class_templates.php'); + $TPL=NEW TEMPLATE; + $TPL->open(SERVER_ROOT.'/templates/new_registration.tpl'); + + $TPL->set('Username',$_REQUEST['username']); + $TPL->set('TorrentKey',$torrent_pass); + $TPL->set('SITE_NAME',SITE_NAME); + $TPL->set('SITE_URL',SITE_URL); + + send_email($_REQUEST['email'],'New account confirmation at '.SITE_NAME,$TPL->get(),'noreply'); + update_tracker('add_user', array('id' => $UserID, 'passkey' => $torrent_pass)); + $Sent=1; + + + } + + } elseif($_GET['invite']) { + // If they haven't submitted the form, check to see if their invite is good + $DB->query("SELECT InviteKey FROM invites WHERE InviteKey='".db_string($_GET['invite'])."'"); + if($DB->record_count() == 0){ + error('Invite not found!'); + } + } + + include('step1.php'); + +} elseif(!OPEN_REGISTRATION) { + if (isset($_GET['welcome'])) { + include('code.php'); + } else { + include('closed.php'); + } +} +?> diff --git a/sections/register/step1.php b/sections/register/step1.php new file mode 100644 index 00000000..0b798e7a --- /dev/null +++ b/sections/register/step1.php @@ -0,0 +1,65 @@ +GenerateJS('regform'); +?> +
    +
    + +'."\n"; + } + if(!empty($Err)) { +?> +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Username  + +

    It is recommended that you do NOT use your real name for personal security! We will not be changing it for you.

    +
    Email 
    Password 
    Verify Password 
    checked="checked" />
    checked="checked" />
    checked="checked" />
    + + An email has been sent to the address that you provided. After you confirm your email address you will be able to log into your account. + + +
    +
    + +
    + Congratulations! Your account has been created.
    + You can now log into your account using the login page. +
    + diff --git a/sections/reports/array.php b/sections/reports/array.php new file mode 100644 index 00000000..641a41a0 --- /dev/null +++ b/sections/reports/array.php @@ -0,0 +1,99 @@ + array( + "title" => "User", + "guidelines" => array( + "The Report User option is for reporting a user who has broken one of the golden rules outlined here, or if you need to alert staff to something specific about a user that cannot be reported elsewhere.", + "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.", + "Please do not report a user in this section for breaking rules such as: +
      +
    • Torrent uploads
    • +
    • Forum threads/posts
    • +
    • Collages
    • +
    • Requests
    • +
    ", + "These have their own specific section for reporting, found on their respective pages.", + "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue." + ) + ), + "request_update" => array( + "title" => "Request (Update)", + "guidelines" => array( + "This option is for asking the moderators to update your request to the new system.", + "If your request has no other votes, you can just edit it yourself!", + "Please do not report every single request on the old system, but only those that you really want updated. That way we can move them over in an order that benefits you most.", + "If possible, please include a discogs link in the comments field." + ) + ), + "request" => array( + "title" => "Request", + "guidelines" => array( + "The report request option is for reporting a request which breaks any of the rules found here.", + "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.", + "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue.", + "If you are reporting this request to get it updated to the new requests system, please go back and click '[Request Update]'." + ) + ), + "requests_comment" => array( + "title" => "Request Comment", + "guidelines" => array( + "The Report comment option is specifically for reporting when the Chat Rules have been broken.", + "Such as posts containing racism, offensive language, flaming, pornography, and other rules violations.", + "We encourage all users to use this feature when they see a rules violation of any form.", + "This will get quicker action than PMing a staff member will.", + "Please restrict the use of this feature to reporting Rules violations, and remember, this is for reporting comments, not replying to them." + ) + ), + "thread" => array( + "title" => "Forum Thread", + "guidelines" => array( + "The Report Thread option is specifically for reporting when the Chat Rules have been broken. Such as posts containing racism, offensive language, flaming, pornography, and other rules violations. We encourage all users to use this feature when they see a rules violation of any form.", + "This will get quicker action than PMing a staff member will.", + "Please restrict the use of this feature to reporting Rules violations, and remember, this is for reporting threads, not replying to them." + ) + ), + "post" => array( + "title" => "Forum Post", + "guidelines" => array( + "The Report comment option is specifically for reporting when the Chat Rules have been broken.", + "Such as posts containing racism, offensive language, flaming, pornography, and other rules violations.", + "We encourage all users to use this feature when they see a rules violation of any form.", + "This will get quicker action than PMing a staff member will.", + "Please restrict the use of this feature to reporting Rules violations, and remember, this is for reporting comments, not replying to them." + ) + ), + "collage" => array( + "title" => "Collage", + "guidelines" => array( + "The report collage option is for reporting a collage which breaks one of the collage guidelines found on the collage rules page.", + "Collage rules are an interpreted concept, and it is up to staff to interpret these rules. If you feel like this collage might be a borderline case between allowed and not allowed, feel free to report it and we will look into it.", + "We encourage all users to use this feature whenever possible. This will get quicker action than PMing a staff member will.", + "In your report description below, please be specific and include as much information as possible that will help our staff resolve the issue." + ) + ), + "collages_comment" => array( + "title" => "Collage Comment", + "guidelines" => array( + "The Report comment option is specifically for reporting when the Chat Rules have been broken.", + "Such as posts containing racism, offensive language, flaming, pornography, and other rules violations.", + "We encourage all users to use this feature when they see a rules violation of any form.", + "This will get quicker action than PMing a staff member will.", + "Please restrict the use of this feature to reporting Rules violations, and remember, this is for reporting comments, not replying to them." + ) + ), + "torrents_comment" => array( + "title" => "Torrent Comment", + "guidelines" => array( + "The Report comment option is specifically for reporting when the Chat Rules have been broken.", + "Such as posts containing racism, offensive language, flaming, pornography, and other rules violations.", + "We encourage all users to use this feature when they see a rules violation of any form.", + "This will get quicker action than PMing a staff member will.", + "Please restrict the use of this feature to reporting Rules violations, and remember, this is for reporting comments, not replying to them." + ) + ) + ); +?> diff --git a/sections/reports/index.php b/sections/reports/index.php new file mode 100644 index 00000000..13409082 --- /dev/null +++ b/sections/reports/index.php @@ -0,0 +1,23 @@ + diff --git a/sections/reports/report.php b/sections/reports/report.php new file mode 100644 index 00000000..a66b4d0f --- /dev/null +++ b/sections/reports/report.php @@ -0,0 +1,290 @@ +query("SELECT Username FROM users_main WHERE ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Username) = $DB->next_record(); + break; + + case "request_update" : + $NoReason = true; + $DB->query("SELECT Title, Description, TorrentID, CategoryID, Year FROM requests WHERE ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Name, $Desc, $Filled, $CategoryID, $Year) = $DB->next_record(); + if($Filled || ($CategoryID != 0 && ($Categories[$CategoryID-1] != "Music" || $Year != 0))) { + error(403); + } + break; + + case "request" : + $DB->query("SELECT Title, Description, TorrentID FROM requests WHERE ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Name, $Desc, $Filled) = $DB->next_record(); + break; + + case "collage" : + $DB->query("SELECT Name, Description FROM collages WHERE ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Name, $Desc) = $DB->next_record(); + break; + + case "thread" : + $DB->query("SELECT ft.Title, ft.ForumID, um.Username FROM forums_topics AS ft JOIN users_main AS um ON um.ID=ft.AuthorID WHERE ft.ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Title, $ForumID, $Username) = $DB->next_record(); + $DB->query("SELECT MinClassRead FROM forums WHERE ID = ".$ForumID); + list($MinClassRead) = $DB->next_record(); + if(!empty($LoggedUser['DisableForums']) || + ($MinClassRead > $LoggedUser['Class'] && (!isset($LoggedUser['CustomForums'][$ForumID]) || $LoggedUser['CustomForums'][$ForumID] == 0)) || + (isset($LoggedUser['CustomForums'][$ForumID]) && $LoggedUser['CustomForums'][$ForumID] == 0)) { + error(403); + } + break; + + case "post" : + $DB->query("SELECT fp.Body, fp.TopicID, um.Username FROM forums_posts AS fp JOIN users_main AS um ON um.ID=fp.AuthorID WHERE fp.ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Body, $TopicID, $Username) = $DB->next_record(); + $DB->query("SELECT ForumID FROM forums_topics WHERE ID = ".$TopicID); + list($ForumID) = $DB->next_record(); + $DB->query("SELECT MinClassRead FROM forums WHERE ID = ".$ForumID); + list($MinClassRead) = $DB->next_record(); + if(!empty($LoggedUser['DisableForums']) || + ($MinClassRead > $LoggedUser['Class'] && (!isset($LoggedUser['CustomForums'][$ForumID]) || $LoggedUser['CustomForums'][$ForumID] == 0)) || + (isset($LoggedUser['CustomForums'][$ForumID]) && $LoggedUser['CustomForums'][$ForumID] == 0)) { + error(403); + } + break; + + case "requests_comment" : + case "torrents_comment" : + case "collages_comment" : + $Table = $Short.'s'; + if($Short == "collages_comment") { + $Column = "UserID"; + } else { + $Column = "AuthorID"; + } + $DB->query("SELECT ".$Short.".Body, um.Username FROM ".$Table." AS ".$Short." JOIN users_main AS um ON um.ID=".$Short.".".$Column." WHERE ".$Short.".ID=".$ID); + if($DB->record_count() < 1) { + error(404); + } + list($Body, $Username) = $DB->next_record(); + break; +} + +show_header('Report a '.$Type['title'],'bbcode'); +?> +
    +

    Report

    +

    Reporting guidelines

    +
    +

    Following these guidelines will help the moderators deal with your report in a timely fashion.

    +
      + +
    • + +
    +

    In short, please include as much detail as possible when reporting. Thank you.

    +
    + +

    You are reporting the user

    + +

    You are reporting the request:

    + + + + + + + + + + + +
    TitleDescriptionFilled?
    full_format($Desc)?>
    +
    + +
    +

    It will greatly increase the turnover rate of the updates if you can fill in as much of the following details in as possible

    +
    + + + + + + + + + + + + + + + + + +
    Year (required) + +
    Release Type + +
    Comment + +
    +
    +
    + +
    +
    + +

    You are reporting the request:

    + + + + + + + + + + + +
    TitleDescriptionFilled?
    full_format($Desc)?>
    + +

    You are reporting the collage:

    + + + + + + + + + +
    TitleDescription
    full_format($Desc)?>
    + +

    You are reporting the thread:

    + + + + + + + + + +
    UsernameTitle
    + +

    You are reporting the post:

    + + + + + + + + + +
    UsernameBody
    full_format($Body)?>
    + +

    You are reporting the :

    + + + + + + + + + +
    UsernameBody
    full_format($Body)?>
    + +

    Reason

    +
    +
    + + + + +

    + +
    +
    + ?> +
    + + diff --git a/sections/reports/reports.php b/sections/reports/reports.php new file mode 100644 index 00000000..251c96bd --- /dev/null +++ b/sections/reports/reports.php @@ -0,0 +1,223 @@ +query("SELECT SQL_CALC_FOUND_ROWS + r.ID, + r.UserID, + um.Username, + r.ThingID, + r.Type, + r.ReportedTime, + r.Reason, + r.Status + FROM reports AS r + JOIN users_main AS um ON r.UserID=um.ID + WHERE ".$Where." + ORDER BY ReportedTime + DESC LIMIT ".$Limit); + +// Number of results (for pagination) +$DB->query('SELECT FOUND_ROWS()'); +list($Results) = $DB->next_record(); + +// Done with the number of results. Move $DB back to the result set for the reports +$DB->set_query_id($Reports); + +// Start printing stuff +?> +
    +

    Active Reports

    + + +next_record()) { + $Type = $Types[$Short]; + $Reference = "reports.php?id=".$ReportID."#report".$ReportID; +?> +
    +
    +
    + + + +
    + + + + + + + + + + + + + + + + + +
    Report was reported by
    + +query("SELECT Username FROM users_main WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No user with the reported ID found"; + } else { + list($Username) = $DB->next_record(); + echo "".display_str($Username).""; + } + break; + case "request" : + case "request_update" : + $DB->query("SELECT Title FROM requests WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No request with the reported ID found"; + } else { + list($Name) = $DB->next_record(); + echo "".display_str($Name).""; + } + break; + case "collage" : + $DB->query("SELECT Name FROM collages WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No collage with the reported ID found"; + } else { + list($Name) = $DB->next_record(); + echo "".display_str($Name).""; + } + break; + case "thread" : + $DB->query("SELECT Title FROM forums_topics WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No thread with the reported ID found"; + } else { + list($Title) = $DB->next_record(); + echo "".display_str($Title).""; + } + break; + case "post" : + if (isset($LoggedUser['PostsPerPage'])) { + $PerPage = $LoggedUser['PostsPerPage']; + } else { + $PerPage = POSTS_PER_PAGE; + } + $DB->query("SELECT p.ID, p.Body, p.TopicID, (SELECT COUNT(ID) FROM forums_posts WHERE forums_posts.TopicID = p.TopicID AND forums_posts.ID<=p.ID) AS PostNum FROM forums_posts AS p WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No post with the reported ID found"; + } else { + list($PostID,$Body,$TopicID,$PostNum) = $DB->next_record(); + echo "POST"; + } + break; + case "requests_comment" : + $DB->query("SELECT rc.RequestID, rc.Body, (SELECT COUNT(ID) FROM requests_comments WHERE ID <= ".$ThingID." AND requests_comments.RequestID = rc.RequestID) AS CommentNum FROM requests_comments AS rc WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No comment with the reported ID found"; + } else { + list($RequestID, $Body, $PostNum) = $DB->next_record(); + $PageNum = ceil($PostNum / TORRENT_COMMENTS_PER_PAGE); + echo "COMMENT"; + } + break; + case "torrents_comment" : + $DB->query("SELECT tc.GroupID, tc.Body, (SELECT COUNT(ID) FROM torrents_comments WHERE ID <= ".$ThingID." AND torrents_comments.GroupID = tc.GroupID) AS CommentNum FROM torrents_comments AS tc WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No comment with the reported ID found"; + } else { + list($GroupID, $Body, $PostNum) = $DB->next_record(); + $PageNum = ceil($PostNum / TORRENT_COMMENTS_PER_PAGE); + echo "COMMENT"; + } + break; + case "collages_comment" : + $DB->query("SELECT cc.CollageID, cc.Body, (SELECT COUNT(ID) FROM collages_comments WHERE ID <= ".$ThingID." AND collages_comments.CollageID = cc.CollageID) AS CommentNum FROM collages_comments AS cc WHERE ID=".$ThingID); + if($DB->record_count() < 1) { + echo "No comment with the reported ID found"; + } else { + list($CollageID, $Body, $PostNum) = $DB->next_record(); + $PerPage = POSTS_PER_PAGE; + $PageNum = ceil($PostNum / $PerPage); + echo "COMMENT"; + } + break; + } +?> + +
    full_format($Reason)?>
    + +
    +
    +
    +
    +set_query_id($Reports); +} +?> +
    + + diff --git a/sections/reports/stats.php b/sections/reports/stats.php new file mode 100644 index 00000000..5adf01bd --- /dev/null +++ b/sections/reports/stats.php @@ -0,0 +1,109 @@ + +

    Other reports stats!

    +
    +
    +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reports AS r JOIN users_main AS um ON um.ID=r.ResolverID WHERE r.ReportedTime > '2009-08-21 22:39:41' AND r.ReportedTime > NOW() - INTERVAL 24 HOUR GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + + + + + + +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reports AS r JOIN users_main AS um ON um.ID=r.ResolverID WHERE r.ReportedTime > '2009-08-21 22:39:41' AND r.ReportedTime > NOW() - INTERVAL 1 WEEK GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + + + +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reports AS r JOIN users_main AS um ON um.ID=r.ResolverID WHERE r.ReportedTime > '2009-08-21 22:39:41' AND r.ReportedTime > NOW() - INTERVAL 1 MONTH GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + + + + +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reports AS r JOIN users_main AS um ON um.ID=r.ResolverID GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + + + +
    Reports resolved in the last 24h + + + + + + + + + + + +
    UsernameReports
    +
    Reports resolved in the last week + + + + + + + + + + + +
    UsernameReports
    +
    Reports resolved in the last month + + + + + + + + + + + +
    UsernameReports
    +
    Reports resolved since 'other' reports (2009-08-21) + + + + + + + + + + + +
    UsernameReports
    +
    +
    + diff --git a/sections/reports/takereport.php b/sections/reports/takereport.php new file mode 100644 index 00000000..12136205 --- /dev/null +++ b/sections/reports/takereport.php @@ -0,0 +1,92 @@ +query("SELECT p.ID, p.TopicID, (SELECT COUNT(ID) FROM forums_posts WHERE forums_posts.TopicID = p.TopicID AND forums_posts.ID<=p.ID) AS PostNum FROM forums_posts AS p WHERE ID=".$ID); + list($PostID,$TopicID,$PostNum) = $DB->next_record(); + $Link = "forums.php?action=viewthread&threadid=".$TopicID."&post=".$PostNum."#post".$PostID; + break; + case "requests_comment" : + $DB->query("SELECT rc.RequestID, rc.Body, (SELECT COUNT(ID) FROM requests_comments WHERE ID <= ".$ID." AND requests_comments.RequestID = rc.RequestID) AS CommentNum FROM requests_comments AS rc WHERE ID=".$ID); + list($RequestID, $Body, $PostNum) = $DB->next_record(); + $PageNum = ceil($PostNum / TORRENT_COMMENTS_PER_PAGE); + $Link = "requests.php?action=view&id=".$RequestID."&page=".$PageNum."#post".$ID.""; + break; + case "torrents_comment" : + $DB->query("SELECT tc.GroupID, tc.Body, (SELECT COUNT(ID) FROM torrents_comments WHERE ID <= ".$ID." AND torrents_comments.GroupID = tc.GroupID) AS CommentNum FROM torrents_comments AS tc WHERE ID=".$ID); + list($GroupID, $Body, $PostNum) = $DB->next_record(); + $PageNum = ceil($PostNum / TORRENT_COMMENTS_PER_PAGE); + $Link = "torrents.php?id=".$GroupID."&page=".$PageNum."#post".$ID; + break; + case "collages_comment" : + $DB->query("SELECT cc.CollageID, cc.Body, (SELECT COUNT(ID) FROM collages_comments WHERE ID <= ".$ID." AND collages_comments.CollageID = cc.CollageID) AS CommentNum FROM collages_comments AS cc WHERE ID=".$ID); + list($CollageID, $Body, $PostNum) = $DB->next_record(); + $PerPage = POSTS_PER_PAGE; + $PageNum = ceil($PostNum / $PerPage); + $Link = "collage.php?action=comments&collageid=".$CollageID."&page=".$PageNum."#post".$ID; + break; +} + +$DB->query("INSERT INTO reports + (UserID, ThingID, Type, ReportedTime, Reason) + VALUES + (".db_string($LoggedUser['ID']).", ".$ID." , '".$Short."', '".sqltime()."', '".db_string($Reason)."')"); +$ReportID = $DB->inserted_id(); + +$Channels = array(); + +if($Short == "request_update") { + $Channels[] = "#requestedits"; + $Cache->increment('num_update_reports'); +} +if(in_array($Short, array('collages_comment', 'Post', 'requests_comment', 'thread', 'torrents_comment'))) { + $Channels[] = "#forumreports"; +} + +foreach($Channels as $Channel) { + send_irc("PRIVMSG ".$Channel." :".$ReportID." - ".$LoggedUser['Username']." just reported a ".$Short.": http://".NONSSL_SITE_URL."/".$Link." : ".$Reason); +} + +$Cache->delete_value('num_other_reports'); + +header('Location: '.$Link); +?> diff --git a/sections/reports/takeresolve.php b/sections/reports/takeresolve.php new file mode 100644 index 00000000..2fd422df --- /dev/null +++ b/sections/reports/takeresolve.php @@ -0,0 +1,58 @@ +query("SELECT Type FROM reports WHERE ID = ".$ReportID); +list($Type) = $DB->next_record(); +if(!check_perms('admin_reports')) { + if(check_perms('site_moderate_forums')) { + if(!in_array($Type, array('collages_comment', 'post', 'requests_comment', 'thread', 'torrents_comment'))) { + error($Type); + } + } else if(check_perms('project_team')) { + if($Type != "request_update") { + error(403); + } + } +} + +$DB->query("UPDATE reports + SET Status='Resolved', + ResolvedTime='".sqltime()."', + ResolverID='".$LoggedUser['ID']."' + WHERE ID='".db_string($ReportID)."'"); + + +$Channels = array(); + +if($Type == "request_update") { + $Channels[] = "#requestedits"; + $Cache->decrement('num_update_reports'); +} + +if(in_array($Type, array('collages_comment', 'post', 'requests_comment', 'thread', 'torrents_comment'))) { + $Channels[] = "#forumreports"; + $Cache->decrement('num_forum_reports'); +} + + +$DB->query("SELECT COUNT(ID) FROM reports WHERE Status = 'New'"); +list($Remaining) = $DB->next_record(); + +foreach($Channels as $Channel) { + send_irc("PRIVMSG ".$Channel." :Report ".$ReportID." resolved by ".preg_replace("/^(.{2})/", "$1·", $LoggedUser['Username'])." on site (".(int)$Remaining." remaining)."); +} + +$Cache->delete_value('num_other_reports'); + +header('Location: reports.php'); +?> diff --git a/sections/reportsv2/ajax_change_resolve.php b/sections/reportsv2/ajax_change_resolve.php new file mode 100644 index 00000000..7d4570d5 --- /dev/null +++ b/sections/reportsv2/ajax_change_resolve.php @@ -0,0 +1,42 @@ + AUTH_KEY + * [torrentid] => TORRENT_ID + * [type] => TYPE + * [otherid] => OTHER_ID + * + * It should not be used on site as is, except in its current use (Switch) as it is lacking for any purpose but this. + */ + +if(!check_perms('admin_reports')){ + error(403); +} + +authorize(); + +if(!is_number($_POST['torrentid'])) { + echo 'No Torrent ID'; + die(); +} else { + $TorrentID = $_POST['torrentid']; +} + +$DB->query("SELECT tg.CategoryID FROM torrents_group AS tg JOIN torrents AS t ON t.GroupID=tg.ID WHERE t.ID = ".$TorrentID); +if($DB->record_count() < 1) { + $Err = "No torrent with that ID exists!"; +} else { + list($CategoryID) = $DB->next_record(); +} + +if(!isset($_POST['type'])) { + echo 'Missing Type'; + die(); +} else if (array_key_exists($_POST['type'], $Types[$CategoryID])) { + $Type = $_POST['type']; + $ReportType = $Types[$CategoryID][$Type]; +} else if(array_key_exists($_POST['type'],$Types['master'])) { + $Type = $_POST['type']; + $ReportType = $Types['master'][$Type]; +} else { + //There was a type but it wasn't an option! + echo 'Wrong type'; + die(); +} + + +$ExtraID = $_POST['otherid']; + +if(!empty($_POST['extra'])) { + $Extra = db_string($_POST['extra']); +} else { + $Extra = ""; +} + +if(!empty($Err)) { + echo $Err; + die(); +} + +$DB->query("SELECT ID FROM reportsv2 WHERE TorrentID=".$TorrentID." AND ReporterID=".db_string($LoggedUser['ID'])." AND ReportedTime > '".time_minus(3)."'"); +if($DB->record_count() > 0) { + die(); +} + +$DB->query("INSERT INTO reportsv2 + (ReporterID, TorrentID, Type, UserComment, Status, ReportedTime, ExtraID) + VALUES + (".db_string($LoggedUser['ID']).", $TorrentID, '".$Type."', '$Extra', 'New', '".sqltime()."', '$ExtraID')"); + +$ReportID = $DB->inserted_id(); + +$Cache->delete_value('reports_torrent_'.$TorrentID); +$Cache->increment('num_torrent_reportsv2'); + +echo $ReportID; +?> diff --git a/sections/reportsv2/ajax_grab_report.php b/sections/reportsv2/ajax_grab_report.php new file mode 100644 index 00000000..34115194 --- /dev/null +++ b/sections/reportsv2/ajax_grab_report.php @@ -0,0 +1,20 @@ +query("UPDATE reportsv2 SET Status='InProgress', ResolverID=".$LoggedUser['ID']." WHERE ID=".$_GET['id']); +if($DB->affected_rows() == 0) { + echo '0'; +} else { + echo '1'; +} diff --git a/sections/reportsv2/ajax_new_report.php b/sections/reportsv2/ajax_new_report.php new file mode 100644 index 00000000..f046ee2b --- /dev/null +++ b/sections/reportsv2/ajax_new_report.php @@ -0,0 +1,444 @@ +query("SELECT + r.ID, + r.ReporterID, + reporter.Username, + r.TorrentID, + r.Type, + r.UserComment, + r.ResolverID, + resolver.Username, + r.Status, + r.ReportedTime, + r.LastChangeTime, + r.ModComment, + r.Track, + r.Image, + r.ExtraID, + r.Link, + r.LogMessage, + tg.Name, + tg.ID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.ArtistID + WHEN 0 THEN '0' + ELSE '0' + END AS ArtistID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.Name + WHEN 0 THEN '' + ELSE 'Various Artists' + END AS ArtistName, + tg.Year, + tg.CategoryID, + t.Time, + t.Remastered, + t.RemasterTitle, + t.RemasterYear, + t.Media, + t.Format, + t.Encoding, + t.Size, + t.HasCue, + t.HasLog, + t.LogScore, + t.UserID AS UploaderID, + t.Tasted, + uploader.Username + FROM reportsv2 AS r + LEFT JOIN torrents AS t ON t.ID=r.TorrentID + LEFT JOIN torrents_group AS tg ON tg.ID=t.GroupID + LEFT JOIN torrents_artists AS ta ON ta.GroupID=tg.ID AND ta.Importance='1' + LEFT JOIN artists_alias AS aa ON aa.AliasID=ta.AliasID + LEFT JOIN users_main AS resolver ON resolver.ID=r.ResolverID + LEFT JOIN users_main AS reporter ON reporter.ID=r.ReporterID + LEFT JOIN users_main AS uploader ON uploader.ID=t.UserID + WHERE r.Status = 'New' + GROUP BY r.ID + ORDER BY ReportedTime ASC + LIMIT 1"); + + + if($DB->record_count() < 1) { + die(); + } + + + list($ReportID, $ReporterID, $ReporterName, $TorrentID, $Type, $UserComment, $ResolverID, $ResolverName, $Status, $ReportedTime, $LastChangeTime, + $ModComment, $Tracks, $Images, $ExtraIDs, $Links, $LogMessage, $GroupName, $GroupID, $ArtistID, $ArtistName, $Year, $CategoryID, $Time, $Remastered, $RemasterTitle, + $RemasterYear, $Media, $Format, $Encoding, $Size, $HasCue, $HasLog, $LogScore, $UploaderID, $UploaderName) = $DB->next_record(MYSQLI_BOTH, array("ModComment")); + + if(!$GroupID) { + //Torrent already deleted + $DB->query("UPDATE reportsv2 SET + Status='Resolved', + LastChangeTime='".sqltime()."', + ModComment='Report already dealt with (Torrent deleted)' + WHERE ID=".$ReportID); +?> +
    + + + + +
    + Report for torrent (deleted) has been automatically resolved. +
    +
    +query("UPDATE reportsv2 SET Status='InProgress', + ResolverID=".$LoggedUser['ID']." + WHERE ID=".$ReportID); + + + if (array_key_exists($Type, $Types[$CategoryID])) { + $ReportType = $Types[$CategoryID][$Type]; + } else if(array_key_exists($Type,$Types['master'])) { + $ReportType = $Types['master'][$Type]; + } else { + //There was a type but it wasn't an option! + $Type = 'other'; + $ReportType = $Types['master']['other']; + } + if ($ArtistID == 0 && empty($ArtistName)) { + $RawName = $GroupName.($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "").($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $LinkName = "$GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")." ".($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $BBName = "[url=torrents.php?id=$GroupID]$GroupName".($Year ? " ($Year)" : "")."[/url] [url=torrents.php?torrentid=$TorrentID][$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")."[/url] ".($HasCue ? " (Cue)" : '').($HasLog ? " [url=torrents.php?action=viewlog&torrentid=$TorrentID&groupid=$GroupID'](Log: $LogScore %)[/url]" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + } elseif ($ArtistID == 0 && $ArtistName == 'Various Artists') { + $RawName = "Various Artists - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "").($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $LinkName = "Various Artists - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")." ".($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $BBName = "Various Artists - [url=torrents.php?id=$GroupID]$GroupName".($Year ? " ($Year)" : "")."[/url] [url=torrents.php?torrentid=$TorrentID][$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")."[/url] ".($HasCue ? " (Cue)" : '').($HasLog ? " [url=torrents.php?action=viewlog&torrentid=$TorrentID&groupid=$GroupID'](Log: $LogScore %)[/url]" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + } else { + $RawName = "$ArtistName - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "").($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $LinkName = "$ArtistName - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")." ".($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $BBName = "[url=artist.php?id=$ArtistID]".$ArtistName."[/url] - [url=torrents.php?id=$GroupID]$GroupName".($Year ? " ($Year)" : "")."[/url] [url=torrents.php?torrentid=$TorrentID][$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")."[/url] ".($HasCue ? " (Cue)" : '').($HasLog ? " [url=torrents.php?action=viewlog&torrentid=$TorrentID&groupid=$GroupID'](Log: $LogScore %)[/url]" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + } + ?> +
    +
    + +
    + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Reported Torrent: + + (Deleted) + + + [DL] + uploaded by +
    +
    was reported by for the reason:
    + query("SELECT r.ID + FROM reportsv2 AS r + LEFT JOIN torrents AS t ON t.ID=r.TorrentID + WHERE r.Status != 'Resolved' + AND t.GroupID=$GroupID"); + $GroupOthers = ($DB->record_count() - 1); + + if($GroupOthers > 0) { ?> + + query("SELECT t.UserID + FROM reportsv2 AS r + JOIN torrents AS t ON t.ID=r.TorrentID + WHERE r.Status != 'Resolved' + AND t.UserID=$UploaderID"); + $UploaderOthers = ($DB->record_count() - 1); + + if($UploaderOthers > 0) { ?> + + query("SELECT DISTINCT req.ID, + req.FillerID, + um.Username, + req.TimeFilled + FROM requests AS req + LEFT JOIN torrents AS t ON t.ID=req.TorrentID + LEFT JOIN reportsv2 AS rep ON rep.TorrentID=t.ID + JOIN users_main AS um ON um.ID=req.FillerID + WHERE rep.Status != 'Resolved' + AND req.TimeFilled > '2010-03-04 02:31:49' + AND req.TorrentID=$TorrentID"); + $Requests = ($DB->record_count()); + if($Requests > 0) { + while(list($RequestID, $FillerID, $FillerName, $FilledTime) = $DB->next_record()) { + ?> +
    + used this torrent to fill this request +
    + +
    Relevant Tracks: + +
    Relevant Links: + local_url($Link)) { + $Link = $local_url; + } + ?> + + +
    Relevant Other Torrents: + query("SELECT + tg.Name, + tg.ID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.ArtistID + WHEN 0 THEN '0' + ELSE '0' + END AS ArtistID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.Name + WHEN 0 THEN '' + ELSE 'Various Artists' + END AS ArtistName, + tg.Year, + t.Time, + t.Remastered, + t.RemasterTitle, + t.RemasterYear, + t.Media, + t.Format, + t.Encoding, + t.Size, + t.HasCue, + t.HasLog, + t.LogScore, + t.UserID AS UploaderID, + uploader.Username + FROM torrents AS t + LEFT JOIN torrents_group AS tg ON tg.ID=t.GroupID + LEFT JOIN torrents_artists AS ta ON ta.GroupID=tg.ID AND ta.Importance='1' + LEFT JOIN artists_alias AS aa ON aa.AliasID=ta.AliasID + LEFT JOIN users_main AS uploader ON uploader.ID=t.UserID + WHERE t.ID='$ExtraID' + GROUP BY tg.ID"); + + list($ExtraGroupName, $ExtraGroupID, $ExtraArtistID, $ExtraArtistName, $ExtraYear, $ExtraTime, $ExtraRemastered, $ExtraRemasterTitle, + $ExtraRemasterYear, $ExtraMedia, $ExtraFormat, $ExtraEncoding, $ExtraSize, $ExtraHasCue, $ExtraHasLog, $ExtraLogScore, $ExtraUploaderID, $ExtraUploaderName) = display_array($DB->next_record()); + + + if($ExtraGroupName) { + if ($ArtistID == 0 && empty($ArtistName)) { + $ExtraLinkName = "$ExtraGroupName".($ExtraYear ? " ($ExtraYear)" : "")." [$ExtraFormat/$ExtraEncoding/$ExtraMedia]".($ExtraRemastered ? " <$ExtraRemasterTitle - $ExtraRemasterYear>" : "")." ".($ExtraHasLog == '1' ? " (Log: $ExtraLogScore %)" : "")." (".number_format($ExtraSize/(1024*1024), 2)." MB)"; + } elseif ($ArtistID == 0 && $ArtistName == 'Various Artists') { + $ExtraLinkName = "Various Artists - $ExtraGroupName".($ExtraYear ? " ($ExtraYear)" : "")." [$ExtraFormat/$ExtraEncoding/$ExtraMedia]".($ExtraRemastered ? " <$ExtraRemasterTitle - $ExtraRemasterYear>" : "")." ".($ExtraHasLog == '1' ? " (Log: $ExtraLogScore %)" : "")." (".number_format($ExtraSize/(1024*1024), 2)." MB)"; + } else { + $ExtraLinkName = "$ExtraArtistName - $ExtraGroupName".($ExtraYear ? " ($ExtraYear)" : "")." [$ExtraFormat/$ExtraEncoding/$ExtraMedia]".($ExtraRemastered ? " <$ExtraRemasterTitle - $ExtraRemasterYear>" : "")." ".($ExtraHasLog == '1' ? " (Log: $ExtraLogScore %)" : "")." (".number_format($ExtraSize/(1024*1024), 2)." MB)"; + } + + ?> + ")?> + + [DL] + uploaded by [Switch] + +
    Relevant Images: + + <?=$Image?> + +
    User Comment:full_format($UserComment)?>
    Report Comment: + + +
    + Resolve + + + + + + Delete + + + + + Warning + + + + Upload + + +    + + + + +
    + PM + : + + + + + +
    Extra Log Message: + /> + Extra Staff Notes: + +
    + + + | + | + | Multi-Resolve + | +
    +
    +
    +
    + diff --git a/sections/reportsv2/ajax_report.php b/sections/reportsv2/ajax_report.php new file mode 100644 index 00000000..b3441bbb --- /dev/null +++ b/sections/reportsv2/ajax_report.php @@ -0,0 +1,91 @@ + +
      + +
    • + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Image(s)(Required)' : '')?> + + +
    + Track Number(s)(Required)' : '')?> + + All' : '')?> +
    + Link(s) to external source(Required)' : '')?> + + +
    + Permalink to relevant other torrent(s)(Required)' : '')?> + + +
    + Comments (Required) + + +
    diff --git a/sections/reportsv2/ajax_take_pm.php b/sections/reportsv2/ajax_take_pm.php new file mode 100644 index 00000000..8ea3c70f --- /dev/null +++ b/sections/reportsv2/ajax_take_pm.php @@ -0,0 +1,74 @@ +query("SELECT ModComment FROM reportsv2 WHERE ID=".$ReportID); +list($ModComment) = $DB->next_record(); +if(isset($ModComment)) { + $DB->query("Update reportsv2 SET ModComment='".$Message."' WHERE ID=".$ReportID); +} diff --git a/sections/reportsv2/ajax_update_resolve.php b/sections/reportsv2/ajax_update_resolve.php new file mode 100644 index 00000000..9ce966d4 --- /dev/null +++ b/sections/reportsv2/ajax_update_resolve.php @@ -0,0 +1,43 @@ + $Value) { + $Priorities[$Key] = $Value['priority']; + } + array_multisort($Priorities, SORT_ASC, $TypeList); +} else { + $TypeList = $Types['master']; +} + +if(!array_key_exists($NewType, $TypeList)) { + echo "No resolve from that category"; + die(); +} + +$DB->query("UPDATE reportsv2 SET Type = '".$NewType."' WHERE ID=".$ReportID); diff --git a/sections/reportsv2/array.php b/sections/reportsv2/array.php new file mode 100644 index 00000000..d43d82ed --- /dev/null +++ b/sections/reportsv2/array.php @@ -0,0 +1,822 @@ + array( + 'dupe' => array( + 'priority' => '1', + 'title' => 'Dupe', + 'report_messages' => array( + 'Please specify a link to the original torrent.' + ), + 'report_fields' => array( + 'sitelink' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => 'Your torrent has been deleted for being a duplicate of another torrent.' + ) + ), + 'banned' => array( + 'priority' => '23', + 'title' => 'Specifically Banned', + 'report_messages' => array( + 'Please specify exactly which entry on the Do Not Upload list this is violating.' + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '4', + 'delete' => '1', + 'pm' => 'The releases on the Do Not Upload list (on the upload page) are currently forbidden from being uploaded from the site. Do not upload them unless your torrent meets a condition specified in the comment.' + ) + ), + 'urgent' => array( + 'priority' => '28', + 'title' => 'Urgent', + 'report_messages' => array( + 'This report type is only for the very urgent reports, usually for personal information being found within a torrent.', + 'Abusing the Urgent reports could result in a warning or worse', + 'As by default this report type gives the staff absolutely no information about the problem, please be as clear as possible in your comments as to the problem' + ), + 'report_fields' => array( + 'sitelink' => '0', + 'track' => '0', + 'link' => '0', + 'image' => '0', + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => '' + ) + ), + 'other' => array( + 'priority' => '20', + 'title' => 'Other', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => '' + ) + ) + ), + '1' => array( //Music Resolves + 'trump' => array( + 'priority' => '2', + 'title' => 'Trump', + 'report_messages' => array( + 'Please list the specific reason(s) the newer torrent trumps the older one.', + 'Please make sure you are reporting the torrent which has been trumped and should be deleted, not the torrent that you think should remain on site.' + ), + + 'report_fields' => array( + 'sitelink' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => 'Your torrent has been deleted as it was trumped by another torrent.' + ) + ), + 'tag_trump' => array ( + 'priority' => '5', + 'title' => 'Tag Trump', + 'report_messages' => array( + 'Please list the specific tag(s) the newer torrent trumps the older one.', + 'Please make sure you are reporting the torrent which has been trumped and should be deleted, not the torrent that you think should remain on site.' + ), + 'report_fields' => array( + 'sitelink' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => '2.3.12. Properly tag your music files. Certain meta tags (e.g. ID3, Vorbis) are required on all music uploads. Make sure to use the proper format tags for your files (e.g. no ID3 tags for FLAC). ID3v2 tags for files are highly recommended over ID3v1. If you upload an album missing one or more of these tags, then another user may add the tags, re-upload, and report yours for deletion.' + + ) + ), + 'vinyl_trump' => array( + 'priority' => '6', + 'title' => 'Vinyl Trump', + 'report_messages' => array( + 'Please list the specific reason(s) the newer torrent trumps the older one.', + 'Please make sure you are reporting the torrent which has been trumped and should be deleted, not the torrent that you think should remain on site.' + ), + + 'report_fields' => array( + 'sitelink' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => 'Your torrent has been deleted as it was trumped by another torrent.' + ) + ), + 'folder_trump' => array ( + 'priority' => '4', + 'title' => 'Bad Folder Name Trump', + 'report_messages' => array( + 'Please list the folder name and what is wrong with it', + 'Please make sure you are reporting the torrent which has been trumped and should be deleted, not the torrent that you think should remain on site.' + ), + 'report_fields' => array( + 'sitelink' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => 'Name your directories with meaningful titles, such as "Artist - Album (Year) - Format." We advise that directory names in your uploads should at least be "Artist - Album (Year) - Format". The minimum acceptable is "Album", although it is preferable to include more information. If the directory name does not include this minimum then another user can rename the directory, re-upload and report yours for deletion. Avoid creating unnecessary nested folders (such as an extra folder for the actual album) inside your properly named directory. Nested folders make it less likely that downloaders leave the torrent unchanged in order to stay seeding.' + ) + ), + 'file_trump' => array ( + 'priority' => '3', + 'title' => 'Bad File Names Trump', + 'report_messages' => array( + 'Please describe what is wrong with the file names.', + 'Please make sure you are reporting the torrent which has been trumped and should be deleted, not the torrent that you think should remain on site.' + ), + 'report_fields' => array( + 'sitelink' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => '2.3.10. File names must accurately reflect the song titles. You may not have file names like 01track.mp3, 02track.mp3, etc. Also, file names with incorrect song titles can be trumped by properly labeled torrents. If you upload an album with improper file names, then another user may fix the file names, re-upload, and report yours for deletion.' + ) + ), + 'tracks_missing' => array( + 'priority' => '24', + 'title' => 'Track(s) Missing', + 'report_messages' => array( + 'Please list the track number and title of the missing track', + 'If possible, please provide a link to Amazon.com or another source showing the proper track listing.' + ), + 'report_fields' => array( + 'track' => '2', + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'All music torrents must represent a complete album. If tracks are available separately, but not released as singles, you may not upload them individually.' + ) + ), + 'discs_missing' => array( + 'priority' => '12', + 'title' => 'Disc(s) Missing', + 'report_messages' => array( + 'If possible, please provide a link to Amazon.com or another source showing the proper track listing.' + ), + 'report_fields' => array( + 'track' => '0', + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'All music torrents must represent a complete release. Albums must not be missing discs in the case of a multi-disc release.' + ) + ), + 'bonus_tracks' => array( + 'priority' => '9', + 'title' => 'Bonus Tracks Only', + 'report_messages' => array( + 'If possible, please provide a link to Amazon.com or another source showing the proper track listing.' + ), + 'report_fields' => array( + 'track' => '0', + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Please note that individual bonus tracks are not allowed to be uploaded without the rest of the album. Bonus tracks are not bonus discs.' + ) + ), + 'transcode' => array( + 'priority' => '25', + 'title' => 'Transcode', + 'report_messages' => array( + "Please list the tracks you checked, and the method used to determine the transcode.", + "If possible, please include at least one screenshot of any spectral analysis done. You may include more than one." + ), + 'report_fields' => array( + 'image' => '0', + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '2', + 'delete' => '1', + 'pm' => 'No transcodes or re-encodes of lossy releases are acceptable here. For more information about transcodes, please visit this wiki page : http://'.NONSSL_SITE_URL.'/wiki.php?action=article&id=14' + ) + ), + 'low' => array( + 'priority' => '17', + 'title' => 'Low Bitrate', + 'report_messages' => array( + "Please tell us the actual bitrate, and the software used to check." + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '2', + 'delete' => '1', + 'pm' => 'Music releases must have an average bitrate of at least 192kbps regardless of the format.' + ) + ), + 'mutt' => array( + 'priority' => '18', + 'title' => 'Mutt Rip', + 'report_messages' => array( + "Please list at least two (2) tracks which have different bitrates and/or encoders." + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '2', + 'delete' => '1', + 'pm' => 'All music torrents must be encoded with a single encoder using the same settings.' + ) + ), + 'single_track' => array( + 'priority' => '27', + 'title' => 'Unsplit Album Rip', + 'report_messages' => array( + "If possible, please provide a link to Amazon.com or another source showing the proper track listing.", + "This option is for uploads of CDs ripped as a single track when it should be split as on the CD", + "This option is not to be confused with uploads of a single track, taken from a CD with multiple tracks (Tracks Missing)" + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Albums must not be ripped or uploaded as a single track.' + ) + ), + 'tags_lots' => array( + 'priority' => '31', + 'title' => 'Bad Tags / No Tags at All', + 'report_messages' => array( + "Please specify which tags are missing, and whether they're missing from all tracks.", + "Ideally, you will replace this torrent with one with fixed tags and report this with the reason 'Tag Trump' <3" + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => 'The [url=http://'.NONSSL_SITE_URL.'/rules.php?p=upload#r2.3.12]Uploading Rules[/url] require all uploads to be properly tagged. Your torrent has been marked as eligible for trumping, which is now visible to all interested users, who may trump your torrent at any time. +[b]You can avoid a 1-week warning by fixing this torrent yourself![/b] It\'s easy, and only takes a few minutes: Add or fix the required tags, and upload a new torrent to the site. Then, report (RP) the bad torrent for the reason "Tag Trump", indicate in the report comments that you have fixed the tags, and provide a link (PL) to the new torrent.' + ) + ), + 'folders_bad' => array( + 'priority' => '30', + 'title' => 'Bad Folder Names', + 'report_messages' => array( + "Please specify the issue with the folder names.", + "Ideally you will replace this torrent with one with fixed folder names and report this with the reason 'Trumped'." + ), + 'report_fields' => array(), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => 'The [url=http://'.NONSSL_SITE_URL.'/rules.php?p=upload#2.3.2]Uploading Rules[/url] require all uploads to have meaningful directory names. Your torrent has been marked as eligible for trumping, which is now visible to all interested users, who may trump your torrent at any time. +[b]You can fix this torrent yourself![/b] It\'s easy, and only takes a few minutes: Add or fix the folder/directory name(s), and upload a new torrent to the site. Then, report (RP) the bad torrent for the reason "Folder Trump", indicate in the report comments that you have fixed the directory name(s), and provide a link (PL) to the new torrent.') + ), + 'wrong_format' => array( + 'priority' => '32', + 'title' => 'Wrong Specified Format', + 'report_messages' => array( + "Please specify the correct format." + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => 'Please be careful when specifying the format of your uploads' + ) + ), + 'wrong_media' => array( + 'priority' => '33', + 'title' => 'Wrong Specified Media', + 'report_messages' => array( + "Please specify the correct media." + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => 'Please be careful when specifying the media of your uploads' + ) + ), + 'format' => array( + 'priority' => '10', + 'title' => 'Disallowed Format', + 'report_messages' => array( + "If applicable, list the relevant tracks" + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'The only formats allowed for music are: MP3, FLAC, Ogg Vorbis, AAC, AC3, DTS' + ) + ), + 'bitrate' => array( + 'priority' => '15', + 'title' => 'Inaccurate Bitrate', + 'report_messages' => array( + "Please tell us the actual bitrate, and the software used to check.", + "If the correct bitrate would make this torrent a duplicate, please report it as a dupe, and include the mislabeling in 'Comments'.", + "If the correct bitrate would result in this torrent trumping another, please report it as a trump, and include the mislabeling in 'Comments'." + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Bitrates must accurately reflect encoder presets or average bitrate of the audio files.' + ) + ), + 'source' => array( + 'priority' => '21', + 'title' => 'Radio/TV/FM/WEB Rip', + 'report_messages' => array( + "Please include as much information as possible to verify the report" + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => "Radio, television, web rips and podcasts are not allowed. It does not matter whether it's FM, direct satellite, internet, or even if it's a pre-broadcast tape." + ) + ), + 'discog' => array( + 'priority' => '13', + 'title' => 'Discography', + 'report_messages' => array( + "Please include as much information as possible to verify the report" + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => "Multi-album torrents are not allowed on the site under any circumstances. That means no discographies, Pitchfork compilations, etc." + ) + ), + 'user_discog' => array( + 'priority' => '29', + 'title' => 'User Compilation', + 'report_messages' => array( + "Please include as much information as possible to verify the report" + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => "User-made compilations are not allowed. Compilations must be reasonably official." + ) + ), + 'lineage' => array( + 'priority' => '19', + 'title' => 'No Lineage Info', + 'report_messages' => array( + "Please list the specific information missing from the torrent (hardware, software, etc.)" + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => "All lossless analog rips must include clear information about source lineage. This information should be displayed in the torrent description. Optionally, the uploader may include the information in a .txt or .log file within the torrent." + ) + ), + 'edited' => array( + 'priority' => '14', + 'title' => 'Edited Log', + 'report_messages' => array( + "Please explain exactly where you believe the log was edited." + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '4', + 'delete' => '1', + 'pm' => "No log editing is permitted. See rule 2.2.15.9." + ) + ), + 'audience' => array( + 'priority' => '7', + 'title' => 'Audience Recording', + 'report_messages' => array( + "Please include as much information as possible to verify the report" + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => "No unofficial audience recordings. Unofficially-mastered audience recordings (AUD) are not allowed here regardless of how rare you think they are." + ) + ), + 'filename' => array( + 'priority' => '8', + 'title' => 'Bad File Names', + 'report_messages' => array( + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => 'Reason: The [url=http://'.NONSSL_SITE_URL.'/rules.php?p=upload#r2.3.10]Uploading Rules[/url] require all uploads to have proper file names. Your torrent has been marked as eligible for trumping, which is now visible to all interested users, who may trump your torrent at any time. You are encouraged to fix this torrent yourself. It\'s easy, and only takes a few minutes: Fix the required file names and upload a new torrent to the site. Then, report (RP) the bad torrent for the reason "Bad File Names Trump," indicate in the report comments that you have fixed the file names, and provide a link (PL) to the new torrent' + ) + ), + 'cassette' => array( + 'priority' => '26', + 'title' => 'Unapproved Cassette', + 'report_messages' => array( + "If the album was never released other than on cassette, please include a source." + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => "Cassette-sourced uploads must be approved by staff first. You must contact a moderator privately for approval before uploading. Unapproved cassette torrents may be reported and deleted if no note exists of prior staff approval." + ) + ), + 'skips' => array( + 'priority' => '22', + 'title' => 'Skips / Encode Errors', + 'report_messages' => array( + "Please tell us which track(s) we should check.", + "Telling us where precisely in the song the skip/encode error can be heard will help us deal with your torrent." + ), + 'report_fields' => array( + 'track' => '2' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => "Music not sourced from vinyl must not contain pops, clicks, or skips. They will be deleted for rip/encode errors if reported. Music that is sourced from vinyl must not have excessive problems." + ) + ), + 'rescore' => array( + 'priority' => '16', + 'title' => 'Log Rescore Request', + 'report_messages' => array( + "It could help us if you say exactly why you believe this log requires rescoring.", + "For example, if it's a foreign log which needs scoring, or if the log wasn't uploaded at all" + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '0', + 'pm' => "" + ) + ), + 'ogg' => array( + 'priority' => '11', + 'title' => 'Disallowed Ogg Preset', + 'report_messages' => array( + "Please include as much information as possible to verify the report" + ), + 'report_fields' => array( + 'track' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => "Only -q8.x (~256 (VBR)) is allowed on the site for Ogg Vorbis. Torrents encoded with presets other than -q8.x will be deleted." + ) + ), + ), + '2' => array( //Applications Rules Broken + 'missing_crack' => array( + 'priority' => '7', + 'title' => 'No Crack/Keygen/Patch', + 'report_messages' => array( + 'Please include as much information as possible to verify the report', + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'All applications must come with a crack, keygen, or other method of ensuring that downloaders can install them easily. App torrents with keygens, cracks, or patches that do not work and torrents missing clear installation instructions are deleted if reported. No exceptions.' + ) + ), + 'game' => array( + 'priority' => '5', + 'title' => 'Game', + 'report_messages' => array( + 'Please include as much information as possible to verify the report', + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '4', + 'delete' => '1', + 'pm' => 'No games of any kind are allowed: whether PC, Mac, phone or any other platform.' + ) + ), + 'free' => array( + 'priority' => '4', + 'title' => 'Freely Available', + 'report_messages' => array( + 'Please include a link to a source of information or to the freely available app itself.', + ), + 'report_fields' => array( + 'link' => '1' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'App releases must not be freely available tools. Application releases cannot be freely downloaded anywhere from any official source. Nor may you upload open source apps where the source code is available for free.' + ) + ), + 'description' => array( + 'priority' => '8', + 'title' => 'No Description', + 'report_messages' => array( + 'If possible, please provide a link to an accurate description', + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Release descriptions for apps must contain good information about the application. You should either have a small description of the program (either taken from its website or from a NFO) or a link to information–ideally both.' + ) + ), + 'pack' => array( + 'priority' => '2', + 'title' => 'Archived Pack', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Sound sample packs, template collections, and font collections are allowed if they are official releases, not freely available, and unarchived.' + ) + ), + 'collection' => array( + 'priority' => '3', + 'title' => 'Collection of Cracks', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Collections of cracks, keygens or serials are not allowed. The crack, keygen or serial for an application must be in a torrent with its corresponding application. It cannot be uploaded separately from the application.' + ) + ), + 'hack' => array( + 'priority' => '6', + 'title' => 'Hacking Tool', + 'report_messages' => array( + 'Please include as much information as possible to verify the report', + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Torrents containing hacking or cracking tools are not allowed.' + ) + ), + 'virus' => array( + 'priority' => '6', + 'title' => 'Contains Virus', + 'report_messages' => array( + 'Please include as much information as possible to verify the report. Please also double check that your virus scanner is not incorrectly identifying a keygen or crack as a virus.', + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'The torrent was determined to be infected with a virus/trojan. In the future, please scan all potential uploads with an antivirus program such as AVG, Avast, or MS Security Essentials.' + ) + ), + 'notwork' => array( + 'priority' => '6', + 'title' => 'Not Working', + 'report_messages' => array( + 'Please include as much information as possible to verify the report.', + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => 'This program was determined to be not fully functional.' + ) + ) + ), + '3' => array( //Ebook Rules Broken + 'unrelated' => array( + 'priority' => '27', + 'title' => 'Unrelated Ebooks', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => 'Collections of eBooks are allowed only if each title is related to each other in a meaningful way.' + ) + ) + ), + '4' => array( //Audiobook Rules Broken + 'skips' => array( + 'priority' => '21', + 'title' => 'Skips / Encode Errors', + 'report_messages' => array( + "Please tell us which track(s) we should check.", + "Telling us where precisely in the song the skip/encode error can be heard will help us deal with your torrent." + ), + 'report_fields' => array( + 'track' => '2' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '0', + 'delete' => '1', + 'pm' => "Music not sourced from vinyl must not contain pops, clicks, or skips. They will be deleted for rip/encode errors if reported. Music that is sourced from vinyl must not have excessive problems." + ) + ) + ), + '5' => array( //E-Learning vidoes Rules Broken + 'dissallowed' => array( + 'priority' => '2', + 'title' => 'Disallowed Topic', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'Tutorials on how to use musical instruments, vocal training, producing music or otherwise learning the theory and practice of music are the only allowed topics.' + ) + ) + ), + '6' => array( //Comedy Rules Broken + 'talkshow' => array( + 'priority' => '27', + 'title' => 'Talkshow/Podcast', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '1', + 'delete' => '1', + 'pm' => 'No radio talk shows and podcasts are allowed.' + ) + ) + ), + '7' => array( //Comics Rules Broken + 'titles' => array( + 'priority' => '18', + 'title' => 'Multiple Comic Titles', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '', + 'delete' => '1', + 'pm' => "Collections may not span more than one comic title. You may not collect multiple different comic titles. e.g. 'The Amazing Spider-Man #1 and The Incredible Hulk #1' Exceptions: Titles may contain more than one comic title if either: it's a recognized comic crossover/event or it's a DCP weekly release." + ) + ), + 'volumes' => array( + 'priority' => '19', + 'title' => 'Multiple Volumes', + 'report_messages' => array( + 'Please include as much information as possible to verify the report' + ), + 'report_fields' => array( + 'link' => '0' + ), + 'resolve_options' => array( + 'upload' => '0', + 'warn' => '', + 'delete' => '1', + 'pm' => "Torrents spanning multiple volumes are too large and must be uploaded as separate volumes." + ) + ) + ) + ); diff --git a/sections/reportsv2/header.php b/sections/reportsv2/header.php new file mode 100644 index 00000000..12800eb7 --- /dev/null +++ b/sections/reportsv2/header.php @@ -0,0 +1,13 @@ + + diff --git a/sections/reportsv2/index.php b/sections/reportsv2/index.php new file mode 100644 index 00000000..74028cf8 --- /dev/null +++ b/sections/reportsv2/index.php @@ -0,0 +1,66 @@ + diff --git a/sections/reportsv2/report.php b/sections/reportsv2/report.php new file mode 100644 index 00000000..eff2fd0d --- /dev/null +++ b/sections/reportsv2/report.php @@ -0,0 +1,86 @@ +query("SELECT tg.CategoryID FROM torrents_group AS tg LEFT JOIN torrents AS t ON t.GroupID=tg.ID WHERE t.ID=".$_GET['id']); + list($CategoryID) = $DB->next_record(); +} + +show_header('Report', 'reportsv2'); +?> + +
    +

    Report a torrent

    + +
    +
    + + + + +
    + + + + + +
    Reason : + +
    + +

    Reporting guidelines

    +
    +

    Fields that contain lists of values (for example, listing more than one track number) should be separated by a space.

    +
    +

    Following the below report type specific guidelines will help the moderators deal with your report in a timely fashion.

    +
    + +
    + + + + + + + + +
    + +
    + +
    +
    + + diff --git a/sections/reportsv2/reports.php b/sections/reportsv2/reports.php new file mode 100644 index 00000000..41f0b8f7 --- /dev/null +++ b/sections/reportsv2/reports.php @@ -0,0 +1,40 @@ + + + +

    New reports, auto assigned!

    +
    + + | + | + | +
    +
    +
    +
    + diff --git a/sections/reportsv2/search.php b/sections/reportsv2/search.php new file mode 100644 index 00000000..c3ed402d --- /dev/null +++ b/sections/reportsv2/search.php @@ -0,0 +1,17 @@ +.> + */ +if(!check_perms('admin_reports')){ + error(403); +} + +show_header('Reports V2!', 'reportsv2'); +include('header.php'); +?> +

    Search

    +
    +On hold until FZeroX fixes the main torrents search, then I will steal all his work and claim it as my own. + \ No newline at end of file diff --git a/sections/reportsv2/static.php b/sections/reportsv2/static.php new file mode 100644 index 00000000..07bce6d0 --- /dev/null +++ b/sections/reportsv2/static.php @@ -0,0 +1,651 @@ +query("SELECT Username FROM users_main WHERE ID=".$ID); + list($Username) = $DB->next_record(); + if($Username) { + $Title = $Username."'s in progress reports"; + } else { + $Title = $ID."'s in progress reports"; + } + $Where = "WHERE r.Status = 'InProgress' AND r.ResolverID = ".$ID; + break; + case "resolver" : + $DB->query("SELECT Username FROM users_main WHERE ID=".$ID); + list($Username) = $DB->next_record(); + if($Username) { + $Title = $Username."'s in resolved reports"; + } else { + $Title = $ID."'s in resolved reports"; + } + $Where = "WHERE r.Status = 'Resolved' AND r.ResolverID = ".$ID; + $Order = "ORDER BY r.LastChangeTime DESC"; + break; + case "group" : + $Title = "Non resolved reports for the group ".$ID; + $Where = "WHERE r.Status != 'Resolved' AND tg.ID = ".$ID; + break; + case "torrent" : + $Title = "All reports for the torrent ".$ID; + $Where = "WHERE r.TorrentID = ".$ID; + break; + case "report" : + $Title = "Seeing resolution of report ".$ID; + $Where = "WHERE r.ID = ".$ID; + break; + case "reporter" : + $DB->query("SELECT Username FROM users_main WHERE ID=".$ID); + list($Username) = $DB->next_record(); + if($Username) { + $Title = "All torrents reported by ".$Username; + } else { + $Title = "All torrents reported by user ".$ID; + } + $Where = "WHERE r.ReporterID = ".$ID; + $Order = "ORDER BY r.ReportedTime DESC"; + break; + case "uploader" : + $DB->query("SELECT Username FROM users_main WHERE ID=".$ID); + list($Username) = $DB->next_record(); + if($Username) { + $Title = "All reports for torrents uploaded by ".$Username; + } else { + $Title = "All reports for torrents uploaded by user ".$ID; + } + $Where = "WHERE r.Status != 'Resolved' AND t.UserID = ".$ID; + break; + case "type": + $Title = "All New reports for the chosen type"; + $Where = "WHERE r.Status = 'New' AND r.Type = '".$ID."'"; + break; + break; + default : + error(404); + break; + } +} + + + +$DB->query("SELECT SQL_CALC_FOUND_ROWS + r.ID, + r.ReporterID, + reporter.Username, + r.TorrentID, + r.Type, + r.UserComment, + r.ResolverID, + resolver.Username, + r.Status, + r.ReportedTime, + r.LastChangeTime, + r.ModComment, + r.Track, + r.Image, + r.ExtraID, + r.Link, + r.LogMessage, + tg.Name, + tg.ID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.ArtistID + WHEN 0 THEN '0' + ELSE '0' + END AS ArtistID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.Name + WHEN 0 THEN '' + ELSE 'Various Artists' + END AS ArtistName, + tg.Year, + tg.CategoryID, + t.Time, + t.Remastered, + t.RemasterTitle, + t.RemasterYear, + t.Media, + t.Format, + t.Encoding, + t.Size, + t.HasCue, + t.HasLog, + t.LogScore, + t.UserID AS UploaderID, + uploader.Username + FROM reportsv2 AS r + LEFT JOIN torrents AS t ON t.ID=r.TorrentID + LEFT JOIN torrents_group AS tg ON tg.ID=t.GroupID + LEFT JOIN torrents_artists AS ta ON ta.GroupID=tg.ID AND ta.Importance='1' + LEFT JOIN artists_alias AS aa ON aa.AliasID=ta.AliasID + LEFT JOIN users_main AS resolver ON resolver.ID=r.ResolverID + LEFT JOIN users_main AS reporter ON reporter.ID=r.ReporterID + LEFT JOIN users_main AS uploader ON uploader.ID=t.UserID " + .$Where." + GROUP BY r.ID " + .$Order." + LIMIT ".$Limit); + +$Reports = $DB->to_array(); + +$DB->query('SELECT FOUND_ROWS()'); +list($Results) = $DB->next_record(); +$PageLinks=get_pages($Page,$Results,REPORTS_PER_PAGE,11); + +show_header('Reports V2!', 'reportsv2,bbcode'); +include('header.php'); + +?> +

    +
    + + + + + | +
    +
    + +
    + + +
    + + + + +
    + No new reports! \o/ +
    +
    +query("UPDATE reportsv2 SET + Status='Resolved', + LastChangeTime='".sqltime()."', + ModComment='Report already dealt with (Torrent deleted)' + WHERE ID=".$ReportID); + $Cache->decrement('num_torrent_reportsv2'); +?> +
    > + + + + +
    + Report for torrent (deleted) has been automatically resolved. +
    +
    +" : "").($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $LinkName = "$GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")." ".($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $BBName = "[url=torrents.php?id=$GroupID]$GroupName".($Year ? " ($Year)" : "")."[/url] [url=torrents.php?torrentid=$TorrentID][$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")."[/url] ".($HasCue ? " (Cue)" : '').($HasLog ? " [url=torrents.php?action=viewlog&torrentid=$TorrentID&groupid=$GroupID'](Log: $LogScore %)[/url]" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + } elseif ($ArtistID == 0 && $ArtistName == 'Various Artists') { + $RawName = "Various Artists - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "").($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $LinkName = "Various Artists - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")." ".($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $BBName = "Various Artists - [url=torrents.php?id=$GroupID]$GroupName".($Year ? " ($Year)" : "")."[/url] [url=torrents.php?torrentid=$TorrentID][$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")."[/url] ".($HasCue ? " (Cue)" : '').($HasLog ? " [url=torrents.php?action=viewlog&torrentid=$TorrentID&groupid=$GroupID'](Log: $LogScore %)[/url]" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + } else { + $RawName = "$ArtistName - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "").($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $LinkName = "$ArtistName - $GroupName".($Year ? " ($Year)" : "")." [$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")." ".($HasCue ? " (Cue)" : '').($HasLog ? " (Log: $LogScore %)" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + $BBName = "[url=artist.php?id=$ArtistID]".$ArtistName."[/url] - [url=torrents.php?id=$GroupID]$GroupName".($Year ? " ($Year)" : "")."[/url] [url=torrents.php?torrentid=$TorrentID][$Format/$Encoding/$Media]".($Remastered ? " <$RemasterTitle - $RemasterYear>" : "")."[/url] ".($HasCue ? " (Cue)" : '').($HasLog ? " [url=torrents.php?action=viewlog&torrentid=$TorrentID&groupid=$GroupID'](Log: $LogScore %)[/url]" : "")." (".number_format($Size/(1024*1024), 2)." MB)"; + } + ?> +
    +
    + +
    + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Reported Torrent: + + (Deleted) + + + [DL] + uploaded by +
    +
    was reported by for the reason:
    + query("SELECT r.ID + FROM reportsv2 AS r + LEFT JOIN torrents AS t ON t.ID=r.TorrentID + WHERE r.Status != 'Resolved' + AND t.GroupID=$GroupID"); + $GroupOthers = ($DB->record_count() - 1); + + if($GroupOthers > 0) { ?> + + query("SELECT t.UserID + FROM reportsv2 AS r + JOIN torrents AS t ON t.ID=r.TorrentID + WHERE r.Status != 'Resolved' + AND t.UserID=$UploaderID"); + $UploaderOthers = ($DB->record_count() - 1); + + if($UploaderOthers > 0) { ?> + + query("SELECT DISTINCT req.ID, + req.FillerID, + um.Username, + req.TimeFilled + FROM requests AS req + LEFT JOIN torrents AS t ON t.ID=req.TorrentID + LEFT JOIN reportsv2 AS rep ON rep.TorrentID=t.ID + JOIN users_main AS um ON um.ID=req.FillerID + WHERE rep.Status != 'Resolved' + AND req.TimeFilled > '2010-03-04 02:31:49' + AND req.TorrentID = $TorrentID"); + $Requests = ($DB->record_count()); + if($Requests > 0) { + while(list($RequestID, $FillerID, $FillerName, $FilledTime) = $DB->next_record()) { + ?> +
    + used this torrent to fill this request +
    + +
    Relevant Tracks: + +
    Relevant Links: + local_url($Link)) { + $Link = $local_url; + } + ?> + + +
    Relevant Other Torrents: + query("SELECT + tg.Name, + tg.ID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.ArtistID + WHEN 0 THEN '0' + ELSE '0' + END AS ArtistID, + CASE COUNT(ta.GroupID) + WHEN 1 THEN aa.Name + WHEN 0 THEN '' + ELSE 'Various Artists' + END AS ArtistName, + tg.Year, + t.Time, + t.Remastered, + t.RemasterTitle, + t.RemasterYear, + t.Media, + t.Format, + t.Encoding, + t.Size, + t.HasCue, + t.HasLog, + t.LogScore, + t.UserID AS UploaderID, + uploader.Username + FROM torrents AS t + LEFT JOIN torrents_group AS tg ON tg.ID=t.GroupID + LEFT JOIN torrents_artists AS ta ON ta.GroupID=tg.ID AND ta.Importance='1' + LEFT JOIN artists_alias AS aa ON aa.AliasID=ta.AliasID + LEFT JOIN users_main AS uploader ON uploader.ID=t.UserID + WHERE t.ID='$ExtraID' + GROUP BY tg.ID"); + + list($ExtraGroupName, $ExtraGroupID, $ExtraArtistID, $ExtraArtistName, $ExtraYear, $ExtraTime, $ExtraRemastered, $ExtraRemasterTitle, + $ExtraRemasterYear, $ExtraMedia, $ExtraFormat, $ExtraEncoding, $ExtraSize, $ExtraHasCue, $ExtraHasLog, $ExtraLogScore, $ExtraUploaderID, $ExtraUploaderName) = display_array($DB->next_record()); + + if($ExtraGroupName) { + if ($ArtistID == 0 && empty($ArtistName)) { + $ExtraLinkName = "$ExtraGroupName".($ExtraYear ? " ($ExtraYear)" : "")." [$ExtraFormat/$ExtraEncoding/$ExtraMedia]".($ExtraRemastered ? " <$ExtraRemasterTitle - $ExtraRemasterYear>" : "")." ".($ExtraHasCue == '1' ? " (Cue)" : '').($ExtraHasLog == '1' ? " (Log: $ExtraLogScore %)" : "")." (".number_format($ExtraSize/(1024*1024), 2)." MB)"; + } elseif ($ArtistID == 0 && $ArtistName == 'Various Artists') { + $ExtraLinkName = "Various Artists - $ExtraGroupName".($ExtraYear ? " ($ExtraYear)" : "")." [$ExtraFormat/$ExtraEncoding/$ExtraMedia]".($ExtraRemastered ? " <$ExtraRemasterTitle - $ExtraRemasterYear>" : "")." ".($ExtraHasCue == '1' ? " (Cue)" : '').($ExtraHasLog == '1' ? " (Log: $ExtraLogScore %)" : "")." (".number_format($ExtraSize/(1024*1024), 2)." MB)"; + } else { + $ExtraLinkName = "$ExtraArtistName - $ExtraGroupName".($ExtraYear ? " ($ExtraYear)" : "")." [$ExtraFormat/$ExtraEncoding/$ExtraMedia]".($ExtraRemastered ? " <$ExtraRemasterTitle - $ExtraRemasterYear>" : "")." ".($ExtraHasCue == '1' ? " (Cue)" : '').($ExtraHasLog == '1' ? " (Log: $ExtraLogScore %)" : "")." (".number_format($ExtraSize/(1024*1024), 2)." MB)"; + } +?> + ")?> + + [DL] + uploaded by [Switch] + +
    Relevant Images: + + <?=$Image?> + +
    User Comment:full_format($UserComment)?>
    In Progress by: + +
    Report Comment: + + +
    + Resolve + + + + + + Delete + + + + + Warning + + + + Upload + + +    + + + + +
    + PM + : + + + + + +
    Extra Log Message: + /> + Extra Staff Notes: + +
    + + + + | + + | + + | Multi-Resolve + | +
    Resolver + +
    Resolve Time + +
    Report Comments + +
    Log Message + +
    + +
    +
    +
    +
    + + +
    + + diff --git a/sections/reportsv2/takereport.php b/sections/reportsv2/takereport.php new file mode 100644 index 00000000..8dd4ebca --- /dev/null +++ b/sections/reportsv2/takereport.php @@ -0,0 +1,130 @@ + $Value) { + if($Value == '1') { + if(empty($_POST[$Field])) { + $Err = "You are missing a required field (".$Field.") for a ".$ReportType['title']." report."; + } + } +} + +if(!empty($_POST['sitelink'])) { + if(preg_match_all('/((https?:\/\/)?([a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*\.)?'.NONSSL_SITE_URL.'\/torrents.php\?(id=[0-9]+\&)?torrentid=([0-9]+))/is', $_POST['sitelink'], $Matches)) { + $ExtraIDs = implode(' ', $Matches[6]); + if(in_array($TorrentID, $Matches[6])) { + $Err = "The extra permalinks you gave included the link to the torrent you're reporting!"; + } + } else { + $Err = "Permalink was incorrect, should look like http://".NONSSL_SITE_URL."/torrents.php?torrentid=12345"; + } +} else { + $ExtraIDs = ""; +} + +if(!empty($_POST['link'])) { + //resource_type://domain:port/filepathname?query_string#anchor + // http:// www .foo.com /bar + if(preg_match_all('/(https?:\/\/)?[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*(:[0-9]{2,5})?(\/(\S)+)?/is', $_POST['link'], $Matches)) { + $Links = implode(' ', $Matches[0]); + } else { + $Err = "The extra links you provided weren't links..."; + } +} else { + $Links = ""; +} + +if(!empty($_POST['image'])) { + if(preg_match("/^(".IMAGE_REGEX.")( ".IMAGE_REGEX.")*$/is", trim($_POST['image']), $Matches)) { + $Images = $Matches[0]; + } else { + $Err = "The extra image links you provided weren't links to images..."; + } +} else { + $Images = ""; +} + +if(!empty($_POST['track'])) { + if(preg_match('/([0-9]+( [0-9]+)*)|All/is', $_POST['track'], $Matches)) { + $Tracks = $Matches[0]; + } else { + $Err = "Tracks should be given in a space seperated list of numbers (No other characters)"; + } +} else { + $Tracks = ""; +} + +if(!empty($_POST['extra'])) { + $Extra = db_string($_POST['extra']); +} else { + $Err = "As useful as blank reports are, could you be a tiny bit more helpful? (Leave a comment)"; +} + +$DB->query("SELECT ID FROM torrents WHERE ID=".$TorrentID); +if($DB->record_count() < 1) { + $Err = "A torrent with that ID doesn't exist!"; +} + +if(!empty($Err)) { + error($Err); + include(SERVER_ROOT.'/sections/reportsv2/report.php'); + die(); +} + +$DB->query("SELECT ID FROM reportsv2 WHERE TorrentID=".$TorrentID." AND ReporterID=".db_string($LoggedUser['ID'])." AND ReportedTime > '".time_minus(3)."'"); +if($DB->record_count() > 0) { + header('Location: torrents.php?torrentid='.$TorrentID); + die(); +} + +$DB->query("INSERT INTO reportsv2 + (ReporterID, TorrentID, Type, UserComment, Status, ReportedTime, Track, Image, ExtraID, Link) + VALUES + (".db_string($LoggedUser['ID']).", $TorrentID, '".db_string($Type)."', '$Extra', 'New', '".sqltime()."', '".db_string($Tracks)."', '".db_string($Images)."', '".db_string($ExtraIDs)."', '".db_string($Links)."')"); + +$ReportID = $DB->inserted_id(); + + +$Cache->delete_value('reports_torrent_'.$TorrentID); + +$Cache->increment('num_torrent_reportsv2'); +header('Location: torrents.php?torrentid='.$TorrentID); +?> diff --git a/sections/reportsv2/takeresolve.php b/sections/reportsv2/takeresolve.php new file mode 100644 index 00000000..2af4de68 --- /dev/null +++ b/sections/reportsv2/takeresolve.php @@ -0,0 +1,292 @@ +query("UPDATE reportsv2 SET + Status='Resolved', + LastChangeTime='".sqltime()."', + ModComment = '".$Comment."', + ResolverID='".$LoggedUser['ID']."' + WHERE ID='".$ReportID."' + AND Status <> 'Resolved'"); + + if($DB->affected_rows() > 0) { + $Cache->delete_value('num_torrent_reportsv2'); + $Cache->delete_value('reports_torrent_'.$TorrentID); + } else { + //Someone beat us to it. Inform the staffer. +?> + + + + +
    + Somebody has already resolved this report + +
    +query("SELECT ID FROM torrents WHERE ID = ".$TorrentID); +$TorrentExists = ($DB->record_count() > 0); +if(!$TorrentExists) { + $DB->query("UPDATE reportsv2 + SET Status='Resolved', + LastChangeTime='".sqltime()."', + ResolverID='".$LoggedUser['ID']."', + ModComment='Report already dealt with (Torrent deleted)' + WHERE ID=".$ReportID); + + $Cache->decrement('num_torrent_reportsv2'); +} + +if($Report) { + //Resolve with a parallel check + $DB->query("UPDATE reportsv2 + SET Status='Resolved', + LastChangeTime='".sqltime()."', + ResolverID='".$LoggedUser['ID']."' + WHERE ID=".$ReportID." + AND Status <> 'Resolved'"); +} + +//See if it we managed to resolve +if($DB->affected_rows() > 0 || !$Report) { + //We did, lets do all our shit + if($Report) { $Cache->decrement('num_torrent_reportsv2'); } + + + if(isset($Escaped['upload'])) { + $Upload = true; + } else { + $Upload = false; + } + + + if($_POST['resolve_type'] == "tags_lots") { + $DB->query("INSERT IGNORE INTO torrents_bad_tags (TorrentID, UserID, TimeAdded) VALUES (".$TorrentID.", ".$LoggedUser['ID']." , '".sqltime()."')"); + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$TorrentID); + list($GroupID) = $DB->next_record(); + $Cache->delete_value('torrents_details_'.$GroupID); + $SendPM = true; + } + + if($_POST['resolve_type'] == "folders_bad") { + $DB->query("INSERT IGNORE INTO torrents_bad_folders (TorrentID, UserID, TimeAdded) VALUES (".$TorrentID.", ".$LoggedUser['ID'].", '".sqltime()."')"); + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$TorrentID); + list($GroupID) = $DB->next_record(); + $Cache->delete_value('torrents_details_'.$GroupID); + $SendPM = true; + } + if($_POST['resolve_type'] == "filename") { + $DB->query("INSERT IGNORE INTO torrents_bad_files (TorrentID, UserID, TimeAdded) VALUES (".$TorrentID.", ".$LoggedUser['ID'].", '".sqltime()."')"); + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$TorrentID); + list($GroupID) = $DB->next_record(); + $Cache->delete_value('torrents_details_'.$GroupID); + $SendPM = true; + } + + //Log and delete + if(isset($Escaped['delete']) && check_perms('users_mod')) { + $DB->query("SELECT Username FROM users_main WHERE ID = ".$UploaderID); + list($UpUsername) = $DB->next_record(); + $Log = "Torrent ".$TorrentID." (".$RawName.") uploaded by ".$UpUsername." was deleted by ".$LoggedUser['Username']; + $Log .= ($Escaped['resolve_type'] == 'custom' ? "" : " for the reason: ".$ResolveType['title']."."); + if(isset($Escaped['log_message']) && $Escaped['log_message'] != "") { + $Log .= " ( ".$Escaped['log_message']." )"; + } + $DB->query("SELECT GroupID FROM torrents WHERE ID = ".$TorrentID); + list($GroupID) = $DB->next_record(); + delete_torrent($TorrentID); + write_log($Log); + $Log = "deleted torrent for the reason: ".$ResolveType['title'].". ( ".$Escaped['log_message']." )"; + write_group_log($GroupID, $TorrentID, $LoggedUser['ID'], $Log, 0); + } else { + $Log = "No log message (Torrent wasn't deleted)"; + } + + //Warnings / remove upload + if($Upload) { + $Cache->begin_transaction('user_info_heavy_'.$UploaderID); + $Cache->update_row(false, array('DisableUpload' => '1')); + $Cache->commit_transaction(0); + + $DB->query("UPDATE users_info SET + DisableUpload='1' + WHERE UserID=".$UploaderID); + } + + if($Warning > 0) { + $WarnLength = $Warning * (7*24*60*60); + $Reason = "Uploader of torrent (".$TorrentID.") ".$RawName." which was resolved with the preset: ".$ResolveType['title']."."; + if($Escaped['admin_message']) { + $Reason .= " (".$Escaped['admin_message'].")."; + } + if($Upload) { + $Reason .= " (Upload privileges Removed)."; + } + + warn_user($UploaderID, $WarnLength, $Reason); + } else { + //This is a bitch for people that don't warn but do other things, it makes me sad. + $AdminComment = ""; + if($Upload) { + //They removed upload + $AdminComment .= "Upload privileges removed by ".$LoggedUser['Username']; + $AdminComment .= "\nReason: Uploader of torrent (".$TorrentID.") ".db_string($RawName)." which was resolved with the preset: ".$ResolveType['title'].". (Report ID: $ReportID)"; + } + if($Escaped['admin_message']) { + //They did nothing of note, but still want to mark it (Or upload and mark) + $AdminComment .= " (".$Escaped['admin_message'].")"; + } + if($AdminComment) { + $AdminComment = date("Y-m-d").' - '.$AdminComment."\n\n"; + + $DB->query("UPDATE users_info SET + AdminComment=CONCAT('".db_string($AdminComment)."',AdminComment) + WHERE UserID='".db_string($UploaderID)."'"); + } + } + + //PM + if($Escaped['uploader_pm'] || $Warning > 0 || isset($Escaped['delete']) || $SendPM) { + if(isset($Escaped['delete'])) { + $PM = "[url=http://".NONSSL_SITE_URL."/torrents.php?torrentid=".$TorrentID."]Your above torrent[/url] was reported and has been deleted.\n\n"; + } else { + $PM = "[url=http://".NONSSL_SITE_URL."/torrents.php?torrentid=".$TorrentID."]Your above torrent[/url] was reported but not deleted.\n\n"; + } + + $Preset = $ResolveType['resolve_options']['pm']; + + if($Preset != "") { + $PM .= "Reason: ".$Preset; + } + + if($Warning > 0) { + $PM .= "\nThis has resulted in a [url=http://".NONSSL_SITE_URL."/wiki.php?action=article&id=218]".$Warning." week warning.[/url]\n"; + } + + if($Upload) { + $PM .= "This has ".($Warning > 0 ? 'also ' : '')."resulted in you losing your upload privileges."; + } + + if($Log) { + $PM = $PM."\nLog Message: ".$Log."\n"; + } + + if($Escaped['uploader_pm']) { + $PM .= "\nMessage from ".$LoggedUser['Username'].": ".$PMMessage; + } + + $PM .= "\n\nReport was handled by [user]".$LoggedUser['Username']."[/user]."; + + send_pm($UploaderID, 0, db_string($Escaped['raw_name']), db_string($PM)); + } + + $Cache->delete_value('reports_torrent_'.$TorrentID); + + //Now we've done everything, update the DB with values + if($Report) { + $DB->query("UPDATE reportsv2 SET + Type = '".$Escaped['resolve_type']."', + LogMessage='".db_string($Log)."', + ModComment='".$Escaped['comment']."' + WHERE ID=".$ReportID); + } +} else { + //Someone beat us to it. Inform the staffer. +?> + + + + +
    + Somebody has already resolved this report + +
    + diff --git a/sections/reportsv2/views.php b/sections/reportsv2/views.php new file mode 100644 index 00000000..1687ea73 --- /dev/null +++ b/sections/reportsv2/views.php @@ -0,0 +1,248 @@ +query("SELECT ID, Username FROM users_main ORDER BY ID ASC LIMIT 1"); +list($OwnerID, $Owner) = $DB->next_record(); +$Owner = display_str($Owner); + +?> +

    Reports v2 Information!

    +
    +
    + +
    +query("SELECT um.ID, um.Username, COUNT(r.ID) AS Reports FROM reportsv2 AS r JOIN users_main AS um ON um.ID=r.ResolverID WHERE r.LastChangeTime > NOW() - INTERVAL 24 HOUR GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + Reports resolved in the last 24 hours + + + + + + + + + + + +
    UsernameReports
    +
    +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reportsv2 AS r JOIN users_main AS um ON um.ID=r.ResolverID WHERE r.LastChangeTime > NOW() - INTERVAL 1 WEEK GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + Reports resolved in the last week + + + + + + + + + + + +
    UsernameReports
    +
    +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reportsv2 AS r JOIN users_main AS um ON um.ID=r.ResolverID WHERE r.LastChangeTime > NOW() - INTERVAL 1 MONTH GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + Reports resolved in the last month + + + + + + + + + + + +
    UsernameReports
    +
    +query("SELECT um.Username, COUNT(r.ID) AS Reports FROM reportsv2 AS r JOIN users_main AS um ON um.ID=r.ResolverID GROUP BY r.ResolverID ORDER BY Reports DESC"); +$Results = $DB->to_array(); +?> + Reports resolved since reportsv2 (2009-07-27) + + + + + + + + + + + +
    UsernameReports
    +
    +

    Different view modes by person

    +
    + By ID of torrent reported. + +
    + By GroupID of torrent reported. + +
    + By Report ID. + +
    + By Reporter ID. + +
    + By uploader ID. + +
    + By resolver ID. + +

    + For browsing anything more complicated than these, use the search feature. +
    +query("SELECT r.ResolverID, + um.Username, + COUNT(r.ID) AS Count, + COUNT(tasted.Tasted) AS Tasted + FROM reportsv2 AS r + LEFT JOIN users_main AS um ON r.ResolverID=um.ID + LEFT JOIN torrents AS tasted ON tasted.ID=r.TorrentID AND tasted.Tasted = '1' + WHERE r.Status = 'InProgress' + GROUP BY r.ResolverID"); + $Staff = $DB->to_array(); +?> + Currently assigned reports by staff member + + + + + + + + + + + + + + +
    Staff memberCurrent CountTasted
    + 's reports + + +
    +
    +

    Different view modes by report type

    +query("SELECT r.Type, + COUNT(r.ID) AS Count + FROM reportsv2 AS r + WHERE r.Status='New' + GROUP BY r.Type"); + $Current = $DB->to_array(); + if(!empty($Current)) { +?> + + + + + + + + + + + +
    TypeCurrent Count
    + + + +
    +
    +
    + diff --git a/sections/requests/functions.php b/sections/requests/functions.php new file mode 100644 index 00000000..f7938be9 --- /dev/null +++ b/sections/requests/functions.php @@ -0,0 +1,80 @@ +get_value('request_artists_'.$RequestID); + if(is_array($Artists)) { + $Results = $Artists; + } else { + $Results = array(); + $DB->query("SELECT ra.ArtistID, + aa.Name, + ra.Importance + FROM requests_artists AS ra + JOIN artists_alias AS aa ON ra.AliasID = aa.AliasID + WHERE ra.RequestID = ".$RequestID." + ORDER BY ra.Importance ASC, + aa.Name ASC;"); + + $ArtistRaw = $DB->to_array(); + foreach($ArtistRaw as $ArtistRow) { + list($ArtistID, $ArtistName, $ArtistImportance) = $ArtistRow; + $Results[$ArtistImportance][] = array('id' => $ArtistID, 'name' => $ArtistName); + } + $Cache->cache_value('request_artists_'.$RequestID, $Results); + } + return $Results; +} + +function get_request_tags($RequestID) { + global $DB; + $DB->query("SELECT rt.TagID, + t.Name + FROM requests_tags AS rt + JOIN tags AS t ON rt.TagID=t.ID + WHERE rt.RequestID = ".$RequestID." + ORDER BY rt.TagID ASC"); + $Tags = $DB->to_array(); + $Results = array(); + foreach($Tags as $TagsRow) { + list($TagID, $TagName) = $TagsRow; + $Results[$TagID]= $TagName; + } + return $Results; +} + +function get_votes_array($RequestID) { + global $Cache, $DB; + + $RequestVotes = $Cache->get_value('request_votes_'.$RequestID); + if(!is_array($RequestVotes)) { + $DB->query("SELECT rv.UserID, + rv.Bounty, + u.Username + FROM requests_votes as rv + LEFT JOIN users_main AS u ON u.ID=rv.UserID + WHERE rv.RequestID = ".$RequestID." + ORDER BY rv.Bounty DESC"); + if($DB->record_count() < 1) { + error(0); + } else { + $Votes = $DB->to_array(); + + $RequestVotes = array(); + $RequestVotes['TotalBounty'] = array_sum($DB->collect('Bounty')); + + foreach($Votes as $Vote) { + list($UserID, $Bounty, $Username) = $Vote; + $VoteArray = array(); + $VotesArray[] = array('UserID' => $UserID, + 'Username' => $Username, + 'Bounty' => $Bounty); + } + + $RequestVotes['Voters'] = $VotesArray; + $Cache->cache_value('request_votes_'.$RequestID, $RequestVotes); + } + } + return $RequestVotes; +} +?> diff --git a/sections/requests/index.php b/sections/requests/index.php new file mode 100644 index 00000000..e6f77829 --- /dev/null +++ b/sections/requests/index.php @@ -0,0 +1,190 @@ +query("SELECT CEIL((SELECT COUNT(ID)+1 FROM requests_comments AS rc WHERE rc.RequestID='".$RequestID."')/".TORRENT_COMMENTS_PER_PAGE.") AS Pages"); + list($Pages) = $DB->next_record(); + + $DB->query("INSERT INTO requests_comments (RequestID,AuthorID,AddedTime,Body) VALUES ( + '".$RequestID."', '".db_string($LoggedUser['ID'])."','".sqltime()."','".db_string($_POST['body'])."')"); + $PostID=$DB->inserted_id(); + + $CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE*$Pages-TORRENT_COMMENTS_PER_PAGE)/THREAD_CATALOGUE); + $Cache->begin_transaction('request_comments_'.$RequestID.'_catalogue_'.$CatalogueID); + $Post = array( + 'ID'=>$PostID, + 'AuthorID'=>$LoggedUser['ID'], + 'AddedTime'=>sqltime(), + 'Body'=>$_POST['body'], + 'EditedUserID'=>0, + 'EditedTime'=>'0000-00-00 00:00:00', + 'Username'=>'' + ); + $Cache->insert('', $Post); + $Cache->commit_transaction(0); + $Cache->increment('request_comments_'.$RequestID); + + header('Location: requests.php?action=view&id='.$RequestID.'&page='.$Pages); + break; + + case 'get_post': + enforce_login(); + if (!$_GET['post'] || !is_number($_GET['post'])) { error(0); } + $DB->query("SELECT Body FROM requests_comments WHERE ID='".db_string($_GET['post'])."'"); + list($Body) = $DB->next_record(MYSQLI_NUM); + + echo trim($Body); + break; + + case 'takeedit_comment': + enforce_login(); + authorize(); + + include(SERVER_ROOT.'/classes/class_text.php'); // Text formatting class + $Text = new TEXT; + + // Quick SQL injection check + if(!$_POST['post'] || !is_number($_POST['post'])) { error(0); } + + // Mainly + $DB->query("SELECT + rc.Body, + rc.AuthorID, + rc.RequestID, + rc.AddedTime + FROM requests_comments AS rc + WHERE rc.ID='".db_string($_POST['post'])."'"); + list($OldBody, $AuthorID,$RequestID,$AddedTime)=$DB->next_record(); + + $DB->query("SELECT ceil(COUNT(ID) / ".POSTS_PER_PAGE.") AS Page FROM requests_comments WHERE RequestID = $RequestID AND ID <= $_POST[post]"); + list($Page) = $DB->next_record(); + + if ($LoggedUser['ID']!=$AuthorID && !check_perms('site_moderate_forums')) { error(404); } + if ($DB->record_count()==0) { error(404); } + + // Perform the update + $DB->query("UPDATE requests_comments SET + Body = '".db_string($_POST['body'])."', + EditedUserID = '".db_string($LoggedUser['ID'])."', + EditedTime = '".sqltime()."' + WHERE ID='".db_string($_POST['post'])."'"); + + // Update the cache + $CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE*$Page-TORRENT_COMMENTS_PER_PAGE)/THREAD_CATALOGUE); + $Cache->begin_transaction('request_comments_'.$RequestID.'_catalogue_'.$CatalogueID); + + $Cache->update_row($_POST['key'], array( + 'ID'=>$_POST['post'], + 'AuthorID'=>$AuthorID, + 'AddedTime'=>$AddedTime, + 'Body'=>$_POST['body'], + 'EditedUserID'=>db_string($LoggedUser['ID']), + 'EditedTime'=>sqltime(), + 'Username'=>$LoggedUser['Username'] + )); + $Cache->commit_transaction(0); + + $DB->query("INSERT INTO comments_edits (Page, PostID, EditUser, EditTime, Body) + VALUES ('requests', ".db_string($_POST['post']).", ".db_string($LoggedUser['ID']).", '".sqltime()."', '".db_string($OldBody)."')"); + + // This gets sent to the browser, which echoes it in place of the old body + echo $Text->full_format($_POST['body']); + break; + + case 'delete_comment': + enforce_login(); + authorize(); + + // Quick SQL injection check + if (!$_GET['postid'] || !is_number($_GET['postid'])) { error(0); } + + // Make sure they are moderators + if (!check_perms('site_moderate_forums')) { error(403); } + + // Get topicid, forumid, number of pages + $DB->query("SELECT DISTINCT + RequestID, + CEIL((SELECT COUNT(rc1.ID) FROM requests_comments AS rc1 WHERE rc1.RequestID=rc.RequestID)/".TORRENT_COMMENTS_PER_PAGE.") AS Pages, + CEIL((SELECT COUNT(rc2.ID) FROM requests_comments AS rc2 WHERE rc2.ID<'".db_string($_GET['postid'])."')/".TORRENT_COMMENTS_PER_PAGE.") AS Page + FROM requests_comments AS rc + WHERE rc.RequestID=(SELECT RequestID FROM requests_comments WHERE ID='".db_string($_GET['postid'])."')"); + list($RequestID,$Pages,$Page)=$DB->next_record(); + + // $Pages = number of pages in the thread + // $Page = which page the post is on + // These are set for cache clearing. + + $DB->query("DELETE FROM requests_comments WHERE ID='".db_string($_GET['postid'])."'"); + + //We need to clear all subsequential catalogues as they've all been bumped with the absence of this post + $ThisCatalogue = floor((TORRENT_COMMENTS_PER_PAGE*$Page-TORRENT_COMMENTS_PER_PAGE)/THREAD_CATALOGUE); + $LastCatalogue = floor((TORRENT_COMMENTS_PER_PAGE*$Pages-TORRENT_COMMENTS_PER_PAGE)/THREAD_CATALOGUE); + for($i=$ThisCatalogue;$i<=$LastCatalogue;$i++) { + $Cache->delete('request_comments_'.$RequestID.'_catalogue_'.$i); + } + + // Delete thread info cache (eg. number of pages) + $Cache->delete('request_comments_'.$GroupID); + break; + + default: + error(0); + } +} +?> diff --git a/sections/requests/interim.php b/sections/requests/interim.php new file mode 100644 index 00000000..49454797 --- /dev/null +++ b/sections/requests/interim.php @@ -0,0 +1,46 @@ +query("SELECT UserID, FillerID FROM requests WHERE ID = ".$_GET['id']); +list($RequestorID, $FillerID) = $DB->next_record(); + +if($Action == 'unfill') { + if($LoggedUser['ID'] != $RequestorID && $LoggedUser['ID'] != $FillerID && !check_perms('site_moderate_requests')) { + error(403); + } +} elseif($Action == "delete") { + if($LoggedUser['ID'] != $RequestorID && !check_perms('site_moderate_requests')) { + error(403); + } +} + +show_header(ucwords($Action)." Request"); +?> +
    +
    +
    + Request +
    +
    +
    + + + + +
    You will not get your bounty back if you delete this request.
    + + Reason: + + +
    +
    +
    +
    + diff --git a/sections/requests/new_edit.php b/sections/requests/new_edit.php new file mode 100644 index 00000000..34b1f3a1 --- /dev/null +++ b/sections/requests/new_edit.php @@ -0,0 +1,387 @@ + $Val) { + if(strpos($FormatList, $Val) !== false) { + $FormatArray[] = $Key; + } + } + } + + + $MediaArray = array(); + if($MediaList == "Any") { + $MediaArray = array_keys($Media); + } else { + foreach ($Media as $Key => $Val) { + if(strpos($MediaList, $Val) !== false) { + $MediaArray[] = $Key; + } + } + } + } + + $Tags = implode(", ", $Request['Tags']); + } +} + +if($NewRequest && !empty($_GET['artistid']) && is_number($_GET['artistid'])) { + $DB->query("SELECT Name FROM artists_group WHERE artistid = ".$_GET['artistid']." LIMIT 1"); + list($ArtistName) = $DB->next_record(); + $ArtistForm = array( + 1 => array(array('name' => trim($ArtistName))), + 2 => array(), + 3 => array() + ); +} elseif($NewRequest && !empty($_GET['groupid']) && is_number($_GET['groupid'])) { + $ArtistForm = get_artist($_GET['groupid']); + $DB->query("SELECT tg.Name, + tg.Year, + tg.ReleaseType, + tg.WikiImage, + GROUP_CONCAT(t.Name SEPARATOR ', '), + tg.CategoryID + FROM torrents_group AS tg + JOIN torrents_tags AS tt ON tt.GroupID=tg.ID + JOIN tags AS t ON t.ID=tt.TagID + WHERE tg.ID = ".$_GET['groupid']); + if(list($Title, $Year, $ReleaseType, $Image, $Tags, $CategoryID) = $DB->next_record()) { + $GroupID = trim($_REQUEST['groupid']); + } +} + +show_header(($NewRequest ? "Create a request" : "Edit a request"), 'requests'); +?> +
    +

    + +
    +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Please make sure your request follows the request rules!
    + Type + + +
    Artist(s) + + $ArtistNames) { + foreach($ArtistNames as $Artist) { +?> + + + [+] [-] +
    + + + [+] [-] + +
    Title + +
    Record Label + +
    Catalogue Number + +
    Year + +
    Image + +
    Tags +get_value('genre_tags'); + if(!$GenreTags) { + $DB->query('SELECT Name FROM tags WHERE TagType=\'genre\' ORDER BY Name'); + $GenreTags = $DB->collect('Name'); + $Cache->cache_value('genre_tags', $GenreTags, 3600*6); + } +?> + + +
    + Tags should be comma separated, and you should use a period ('.') to separate words inside a tag - eg. 'hip.hop'. +

    + There is a list of official tags to the left of the text box. Please use these tags instead of 'unofficial' tags (eg. use the official 'drum.and.bass' tag, instead of an unofficial 'dnb' tag.) +
    Release Type + +
    Allowed Formats + /> + NB: You cannot require a log or cue unless FLAC is an allowed format + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    Allowed Bitrates + /> + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + onchange="if(!this.checked) { $('#toggle_bitrates').raw().checked = false; }"/> + +
    Allowed Media + /> + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + onchange="if(!this.checked) { $('#toggle_media').raw().checked = false; }"/> + +
    Description +
    +
    Torrent Group + http://what.cd/torrents.php?id=
    + If this request matches a torrent group already existing on the site, please indicate that here. +
    Torrent Group + http://what.cd/torrents.php?id=
    + This request associated with the above torrent group. + + If this is incorrect, please report this request so that staff can fix it. + + +
    Bounty (MB) + + + + % of this is deducted as tax by the system. +
    Post request information + + + + If you add the entered 100.00 MB of bounty, your new stats will be:
    + Uploaded: + Ratio: +
    + +
    + +
    +
    + + +
    +
    + diff --git a/sections/requests/request.php b/sections/requests/request.php new file mode 100644 index 00000000..30c400a7 --- /dev/null +++ b/sections/requests/request.php @@ -0,0 +1,562 @@ +".$Title." [".$Year."]"; + } else { + $DisplayLink = $ArtistLink.$Title." [".$Year."]"; + } + $FullName = $ArtistName.$Title." [".$Year."]"; + + if($BitrateList != "") { + $BitrateString = implode(", ", explode("|", $BitrateList)); + $FormatString = implode(", ", explode("|", $FormatList)); + $MediaString = implode(", ", explode("|", $MediaList)); + } else { + $BitrateString = "Unknown, please read the description."; + $FormatString = "Unknown, please read the description."; + $MediaString = "Unknown, please read the description."; + } + + if(empty($ReleaseType)) { + $ReleaseName = "Unknown"; + } else { + $ReleaseName = $ReleaseTypes[$ReleaseType]; + } + +} else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + $FullName = $Title." [".$Year."]"; + $DisplayLink = $Title." [".$Year."]"; +} else { + $FullName = $Title; + $DisplayLink = $Title; +} + +//Votes time +$RequestVotes = get_votes_array($RequestID); +$VoteCount = count($RequestVotes['Voters']); +$ProjectCanEdit = (check_perms('project_team') && !$IsFilled && (($CategoryID == 0) || ($CategoryName == "Music" && $Year == 0))); +$UserCanEdit = (!$IsFilled && $LoggedUser['ID'] == $RequestorID && $VoteCount < 2); +$CanEdit = ($UserCanEdit || $ProjectCanEdit || check_perms('site_moderate_requests')); + +show_header('View request: '.$FullName, 'comments,requests,bbcode'); + +?> +
    +

    Requests > >

    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +'.$Group['Name'].'';*/ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Created + by +
    Record Label + +
    Catalogue Number + +
    Release Type + +
    Acceptable Bitrates + +
    Acceptable Formats + +
    Acceptable Media + +
    Required FLAC only extra(s) + +
    Torrent Grouptorrents.php?id=
    Votes + + +  (+) + Costs + +
    Custom Vote (MB) + + + + % of this is deducted as tax by the system. +
    Post vote information +
    + + + + + + + + + + If you add the entered 0.00 MB of bounty, your new stats will be:
    + Uploaded: + Ratio: + +
    +
    Bounty
    Filled + Yes, + by user + + (Unfill) Unfilling a request without a valid, nontrivial reason will result in a warning. + +
    Fill request +
    +
    + + + + /> + Should be the permalink (PL) to the torrent (e.g. http:///torrents.php?torrentid=xxxx). +
    +
    + For User: /> +
    + + +
    +
    +
    + +
    Description
    full_format($Description)?>
    +get_value('request_comments_'.$RequestID); +if($Results === false) { + $DB->query("SELECT + COUNT(c.ID) + FROM requests_comments as c + WHERE c.RequestID = '$RequestID'"); + list($Results) = $DB->next_record(); + $Cache->cache_value('request_comments_'.$RequestID, $Results, 0); +} + +list($Page,$Limit) = page_limit(TORRENT_COMMENTS_PER_PAGE,$Results); + +//Get the cache catalogue +$CatalogueID = floor((TORRENT_COMMENTS_PER_PAGE*$Page-TORRENT_COMMENTS_PER_PAGE)/THREAD_CATALOGUE); +$CatalogueLimit=$CatalogueID*THREAD_CATALOGUE . ', ' . THREAD_CATALOGUE; + +//---------- Get some data to start processing + +// Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page +$Catalogue = $Cache->get_value('request_comments_'.$RequestID.'_catalogue_'.$CatalogueID); +if($Catalogue === false) { + $DB->query("SELECT + c.ID, + c.AuthorID, + c.AddedTime, + c.Body, + c.EditedUserID, + c.EditedTime, + u.Username + FROM requests_comments as c + LEFT JOIN users_main AS u ON u.ID=c.EditedUserID + WHERE c.RequestID = '$RequestID' + ORDER BY c.ID + LIMIT $CatalogueLimit"); + $Catalogue = $DB->to_array(false,MYSQLI_ASSOC); + $Cache->cache_value('request_comments_'.$RequestID.'_catalogue_'.$CatalogueID, $Catalogue, 0); +} + +//This is a hybrid to reduce the catalogue down to the page elements: We use the page limit % catalogue +$Thread = array_slice($Catalogue,((TORRENT_COMMENTS_PER_PAGE*$Page-TORRENT_COMMENTS_PER_PAGE)%THREAD_CATALOGUE),TORRENT_COMMENTS_PER_PAGE,true); +?> + + $Post){ + list($PostID, $AuthorID, $AddedTime, $Body, $EditedUserID, $EditedTime, $EditedUsername) = array_values($Post); + list($AuthorID, $Username, $PermissionID, $Paranoia, $Artist, $Donor, $Warned, $Avatar, $Enabled, $UserTitle) = array_values(user_info($AuthorID)); +?> + + + + + + + + + + +
    + # + by [Report Comment] + - [Quote] + - [Edit] - [Delete] + + + + +
    + + <?=$Username ?>'s avatar + + Default avatar + + +
    +full_format($Body)?> + +
    +
    + + « + + Last edited by + + +
    +
    + + + +
    +

    Post comment

    +
    + + + + + + + + + +
    +
    + + + +
    +
    + + +
    +
    + +
    +
    + diff --git a/sections/requests/requests.php b/sections/requests/requests.php new file mode 100644 index 00000000..09d77b42 --- /dev/null +++ b/sections/requests/requests.php @@ -0,0 +1,575 @@ +set_filter('visible', array(1)); + } +} else { + switch($_GET['type']) { + case 'created': + $Title = 'My requests'; + $SS->set_filter('userid', array($LoggedUser['ID'])); + break; + case 'voted': + if(!empty($_GET['userid'])) { + if(is_number($_GET['userid'])) { + if (!check_paranoia('requestsvoted_list', $UserInfo['Paranoia'], $Perms['Class'], $_GET['userid'])) { error(403); } + $Title = "Requests voted for by ".$UserInfo['Username']; + $SS->set_filter('voter', array($_GET['userid'])); + } else { + error(404); + } + } else { + $Title = "Requests I've voted on"; + $SS->set_filter('voter', array($LoggedUser['ID'])); + } + break; + case 'filled': + if(empty($_GET['userid']) || !is_number($_GET['userid'])) { + error(404); + } else { + if (!check_paranoia('requestsfilled_list', $UserInfo['Paranoia'], $Perms['Class'], $_GET['userid'])) { error(403); } + $Title = "Requests filled by ".$UserInfo['Username']; + $SS->set_filter('fillerid', array($_GET['userid'])); + } + break; + case 'bookmarks': + $Title = 'Your bookmarked requests'; + $BookmarkView = true; + $SS->set_filter('bookmarker', array($LoggedUser['ID'])); + break; + default: + error(404); + } +} + +if($Submitted && empty($_GET['show_filled'])) { + $SS->set_filter('torrentid', array(0)); +} + +if(!empty($_GET['search'])) { + $Words = explode(' ', $_GET['search']); + foreach($Words as $Key => &$Word) { + if($Word[0] == '!' && strlen($Word) > 2) { + if(strpos($Word,'!',1) === false) { + $Word = '!'.$SS->EscapeString(substr($Word,1)); + } else { + $Word = $SS->EscapeString($Word); + } + } elseif(strlen($Word) >= 2) { + $Word = $SS->EscapeString($Word); + } else { + unset($Words[$Key]); + } + } + if(!empty($Words)) { + $Queries[] = "@* ".implode(' ', $Words); + } +} + +if(!empty($_GET['tags'])){ + $Tags = explode(',', $_GET['tags']); + $TagNames = array(); + foreach ($Tags as $Tag) { + $Tag = sanitize_tag($Tag); + if(!empty($Tag)) { + $TagNames[] = $Tag; + } + } + $Tags = get_tags($TagNames); +} + +if(empty($_GET['tags_type']) && !empty($Tags)) { + $_GET['tags_type'] = '0'; + $SS->set_filter('tagid', array_keys($Tags)); +} elseif(!empty($Tags)) { + foreach(array_keys($Tags) as $Tag) { + $SS->set_filter('tagid', array($Tag)); + } +} else { + $_GET['tags_type'] = '1'; +} + +if(!empty($_GET['filter_cat'])) { + $Keys = array_keys($_GET['filter_cat']); + $SS->set_filter('categoryid', $Keys); +} + +if(!empty($_GET['releases'])) { + $ReleaseArray = $_GET['releases']; + if(count($ReleaseArray) != count($ReleaseTypes)) { + foreach($ReleaseArray as $Index => $Value) { + if(!is_number($Value)) { + error(0); + } + } + + $SS->set_filter('releasetype', $ReleaseArray); + } +} + +if(!empty($_GET['formats'])) { + $FormatArray = $_GET['formats']; + if(count($FormatArray) != count($Formats)) { + $FormatNameArray = array(); + foreach($FormatArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Formats)) { + $FormatNameArray[$Index] = $Formats[$MasterIndex]; + } else { + //Hax + error(0); + } + } + + $Queries[]='@formatlist '.implode(' | ', $FormatNameArray); + } +} + +if(!empty($_GET['media'])) { + $MediaArray = $_GET['media']; + if(count($MediaArray) != count($Media)) { + $MediaNameArray = array(); + foreach($MediaArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Media)) { + $MediaNameArray[$Index] = $Media[$MasterIndex]; + } else { + //Hax + error(0); + } + } + + $Queries[]='@medialist '.implode(' | ', $MediaNameArray); + } +} + +if(!empty($_GET['bitrates'])) { + $BitrateArray = $_GET['bitrates']; + if(count($BitrateArray) != count($Bitrates)) { + $BitrateNameArray = array(); + foreach($BitrateArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Bitrates)) { + $BitrateNameArray[$Index] = $SS->EscapeString($Bitrates[$MasterIndex]); + } else { + //Hax + error(0); + } + } + + $Queries[]='@bitratelist '.implode(' | ', $BitrateNameArray); + } +} + +if(!empty($_GET['requestor']) && check_perms('site_see_old_requests')) { + if(is_number($_GET['requestor'])) { + $SS->set_filter('userid', array($_GET['requestor'])); + } else { + error(404); + } +} + +if(isset($_GET['year'])) { + if(is_number($_GET['year']) || $_GET['year'] == 0) { + $SS->set_filter('year', array($_GET['year'])); + } else { + error(404); + } +} + +if(!empty($_GET['page']) && is_number($_GET['page'])) { + $Page = min($_GET['page'], 50000/REQUESTS_PER_PAGE); + $SS->limit(($Page - 1) * REQUESTS_PER_PAGE, REQUESTS_PER_PAGE, 50000); +} else { + $Page = 1; + $SS->limit(0, REQUESTS_PER_PAGE, 50000); +} + +if(empty($_GET['order'])) { + $CurrentOrder = 'created'; + $CurrentSort = 'desc'; + $Way = SPH_SORT_ATTR_DESC; + $NewSort = 'asc'; +} else { + if(in_array($_GET['order'], $OrderWays)) { + $CurrentOrder = $_GET['order']; + if($_GET['sort'] == 'asc' || $_GET['sort'] == 'desc') { + $CurrentSort = $_GET['sort']; + $Way = ($CurrentSort == 'asc' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC); + $NewSort = ($_GET['sort'] == 'asc' ? 'desc' : 'asc'); + } else { + error(404); + } + } else { + error(404); + } +} + +switch($CurrentOrder) { + case 'votes' : + $OrderBy = "Votes"; + break; + case 'bounty' : + $OrderBy = "Bounty"; + break; + case 'created' : + $OrderBy = "TimeAdded"; + break; + case 'lastvote' : + $OrderBy = "LastVote"; + break; + case 'filled' : + $OrderBy = "TimeFilled"; + break; + case 'year' : + $OrderBy = "Year"; + break; + default : + $OrderBy = "TimeAdded"; + break; +} +//print($Way); print($OrderBy); die(); +$SS->SetSortMode($Way, $OrderBy); + +if(count($Queries) > 0) { + $Query = implode(' ',$Queries); +} else { + $Query=''; +} + +$SS->set_index('requests requests_delta'); +$SphinxResults = $SS->search($Query, '', 0, array(), '', ''); +$NumResults = $SS->TotalResults; +//We don't use sphinxapi's default cache searcher, we use our own functions + +if(!empty($SphinxResults['notfound'])) { + $SQLResults = get_requests($SphinxResults['notfound']); + if(is_array($SQLResults['notfound'])) { + //Something wasn't found in the db, remove it from results + reset($SQLResults['notfound']); + foreach($SQLResults['notfound'] as $ID) { + unset($SQLResults['matches'][$ID]); + unset($SphinxResults['matches'][$ID]); + } + } + + // Merge SQL results with memcached results + foreach($SQLResults['matches'] as $ID => $SQLResult) { + $SphinxResults['matches'][$ID] = $SQLResult; + + //$Requests['matches'][$ID] = array_merge($Requests['matches'][$ID], $SQLResult); + //We ksort because depending on the filter modes, we're given our data in an unpredictable order + //ksort($Requests['matches'][$ID]); + } +} + +$PageLinks = get_pages($Page, $NumResults, REQUESTS_PER_PAGE); + +$Requests = $SphinxResults['matches']; + +$CurrentURL = get_url(array('order', 'sort')); + +show_header($Title, 'requests'); + +?> +
    +

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Search terms: + +
    Tags (comma-separated): +   + />   + /> +
    Include filled: + checked="checked" /> +
    Include old: + checked="checked" /> +
    Requested by: + +
    + + $CatName) { + if($x%8==0 || $x==1) { +?> + + + + + + +
    + checked="checked" /> + +
    + + + + + + + + + + + + + + + + + +
    Release Types + /> + $Val) { + if($i % 8 == 0) echo "
    ";?> + + /> + +
    Formats + /> + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    Bitrates + /> + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    Media + /> + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    + + + + +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + $Request) { + + //list($BitrateList, $CatalogueNumber, $CategoryID, $Description, $FillerID, $FormatList, $RequestID, $Image, $LogCue, $MediaList, $ReleaseType, + // $Tags, $TimeAdded, $TimeFilled, $Title, $TorrentID, $RequestorID, $RequestorName, $Year, $RequestID, $Categoryid, $FillerID, $LastVote, + // $ReleaseType, $TagIDs, $TimeAdded, $TimeFilled, $TorrentID, $RequestorID, $Voters) = array_values($Request); + + list($RequestID, $RequestorID, $RequestorName, $TimeAdded, $LastVote, $CategoryID, $Title, $Year, $Image, $Description, $CatalogueNumber, $RecordLabel, + $ReleaseType, $BitrateList, $FormatList, $MediaList, $LogCue, $FillerID, $FillerName, $TorrentID, $TimeFilled) = $Request; + + $RequestVotes = get_votes_array($RequestID); + + $VoteCount = count($RequestVotes['Voters']); + + if($CategoryID == 0) { + $CategoryName = "Unknown"; + } else { + $CategoryName = $Categories[$CategoryID - 1]; + } + + $IsFilled = ($TorrentID != 0); + + if($CategoryName == "Music") { + $ArtistForm = get_request_artists($RequestID); + $ArtistLink = display_artists($ArtistForm, true, true); + $FullName = $ArtistLink."".$Title." [".$Year."]"; + } else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + $FullName = "".$Title." [".$Year."]"; + } else { + $FullName ="".$Title.""; + } + + $Row = ($Row == 'a') ? 'b' : 'a'; + + $Tags = $Request['Tags']; +?> + + + + + + + + + + + +
    + Request Name / Year + + Votes + + Bounty + + Filled + + Filled by + + Requested by + + Created + + Last Vote +
    + Nothing found! +
    + +
    + $TagName) { + $TagList[] = "".display_str($TagName).""; + } + $TagList = implode(', ', $TagList); +?> + +
    +
    +
    + + + + +    (+) +
    + +
    + + + + + + No + + + + + + -- + + + + + + + +
    + +
    + diff --git a/sections/requests/requests.php.presphinx b/sections/requests/requests.php.presphinx new file mode 100644 index 00000000..ed749937 --- /dev/null +++ b/sections/requests/requests.php.presphinx @@ -0,0 +1,495 @@ + $Value) { + if(is_number($Value)) { + $Wheres[] = "r.ReleaseType = ".$Value; + } else { + error(0); + } + } + } +} + +if(!empty($_GET['formats'])) { + $FormatArray = $_GET['formats']; + if(count($FormatArray) != count($Formats)) { + $FormatNameArray = array(); + foreach($FormatArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Formats)) { + $FormatNameArray[$Index] = $Formats[$MasterIndex]; + } else { + //Hax + error(0); + } + } + foreach($FormatNameArray as $Index => $Name) { + $Wheres[] = "LOCATE('".db_string($Name)."', r.FormatList)"; + } + } +} + +if(!empty($_GET['media'])) { + $MediaArray = $_GET['media']; + if(count($MediaArray) != count($Media)) { + $MediaNameArray = array(); + foreach($MediaArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Media)) { + $MediaNameArray[$Index] = $Media[$MasterIndex]; + } else { + //Hax + error(0); + } + } + foreach($MediaNameArray as $Index => $Name) { + $Wheres[] = "LOCATE('".db_string($Name)."', r.MediaList)"; + } + } +} + +if(!empty($_GET['bitrates'])) { + $BitrateArray = $_GET['bitrates']; + if(count($BitrateArray) != count($Bitrates)) { + $BitrateNameArray = array(); + foreach($BitrateArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Bitrates)) { + $BitrateNameArray[$Index] = $Bitrates[$MasterIndex]; + } else { + //Hax + error(0); + } + } + foreach($BitrateNameArray as $Index => $Name) { + $Wheres[] = "LOCATE('".db_string($Name)."', r.BitrateList)"; + } + } +} + +if(empty($_GET['type'])) { + $Title = 'Requests'; + if(!check_perms('site_see_old_requests') || empty($_GET['showall'])) { + $Wheres[] = "(TorrentID = 0 OR (TimeFilled > (NOW() - INTERVAL 3 DAY)))"; + } +} else { + switch($_GET['type']) { + case 'created': + $Title = 'My requests'; + $Wheres[] = "r.UserID = ".$LoggedUser['ID']; + break; + case 'voted': + $Title = "Requests I've voted on"; + $Wheres[] = "_rv.UserID = ".$LoggedUser['ID']; + $ExtraJoins[] = "LEFT JOIN requests_votes AS _rv ON _rv.RequestID=r.ID"; + break; + case 'filled': + if(empty($_GET['userid']) || !is_number($_GET['userid'])) { + error(404); + } else { + $Title = "Requests filled"; + $Wheres = "r.FillerID = ".$_GET['userid']; + } + default: + error(404); + } +} + + +if(empty($_GET['order'])) { + $CurrentOrder = 'created'; + $CurrentSort = 'desc'; + $NewSort = 'asc'; +} else { + if(in_array($_GET['order'], $OrderWays)) { + $CurrentOrder = $_GET['order']; + if($_GET['sort'] == 'asc' || $_GET['sort'] == 'desc') { + $CurrentSort = $_GET['sort']; + $NewSort = ($_GET['sort'] == 'asc' ? 'desc' : 'asc'); + } else { + error(404); + } + } else { + error(404); + } +} + +$CurrentURL = get_url(array('order', 'sort')); + +switch($CurrentOrder) { + case 'name' : + $OrderBy = "r.Title"; + break; + case 'votes' : + $OrderBy = "Votes"; + break; + case 'bounty' : + $OrderBy = "Bounty"; + break; + case 'filler' : + $OrderBy = "r.FillerID"; + break; + case 'requestor' : + $OrderBy = "r.UserID"; + break; + case 'created' : + $OrderBy = "r.ID"; + break; + case 'lastvote' : + $OrderBy = "r.LastVote"; + break; + case 'filled' : + $OrderBy = "r.TimeFilled"; + break; + default : + $OrderBy = "r.ID"; + break; +} +$OrderBy = $OrderBy." ".$CurrentSort; + +$Matcher = "AND"; +if(count($Wheres)) { + $Where = "WHERE (".implode(") ".$Matcher." (", $Wheres).")"; +} else { + $Where = ""; +} + +if(count($ExtraJoins)) { + $ExtraJoin = implode(" ", $ExtraJoins); +} else { + $ExtraJoin = ""; +} + +// Build SQL query +$DB->query("SELECT + SQL_CALC_FOUND_ROWS + r.ID, + r.CategoryID, + r.Title, + r.Year, + SUM(rv.Bounty) AS Bounty, + COUNT(rv.UserID) AS Votes, + r.FillerID, + filler.Username, + r.TorrentID, + r.TimeFilled, + r.UserID, + u.Username, + r.TimeAdded, + r.LastVote + FROM requests AS r + LEFT JOIN users_main AS u ON u.ID=r.UserID + LEFT JOIN users_main AS filler ON filler.ID = FillerID + LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID " + .$ExtraJoin." " + .$Where." + GROUP BY r.ID + ORDER BY ".$OrderBy." + LIMIT ".$Limit); + +$Requests = $DB->to_array(); + +$DB->query('SELECT FOUND_ROWS()'); +list($Results) = $DB->next_record(); +$PageLinks = get_pages($Page, $Results, REQUESTS_PER_PAGE, 11); + + + + +show_header($Title, 'requests'); + +?> +
    +

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    Search terms: + +
    Tags (comma-separated): + + />Any   + />All +
    Include filled: + checked="checked" /> +
    Requested by: + +
    + + $CatName) { + if($x%8==0 || $x==1) { +?> + + + + + + +
    + checked="checked" /> + +
    + + + + + + + + + + + + + + + + + +
    Release Types + Toggle All + $Val) { + if($i % 8 == 0) echo "
    ";?> + + /> + +
    Formats + Toggle All + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    Bitrates + Toggle All + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    Media + Toggle All + $Val) { + if($Key % 8 == 0) echo "
    ";?> + + /> + +
    + + + + +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + +".$Title." [".$Year."]"; + } else if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + $FullName = "".$Title." [".$Year."]"; + } else { + $FullName ="".$Title.""; + } + + $Row = ($Row == 'a') ? 'b' : 'a'; + + $Tags = get_request_tags($RequestID); +?> + + + + + + + + + + + +
    + Request Name + + Vote (20MB) + Bounty + + Filled + + Filled by + + Requested by + + Created + + Last Vote +
    + Nothing found! +
    + +
    + $TagName) { + $TagList[] = "".display_str($TagName).""; + } + $TagList = implode(', ', $TagList); +?> + +
    +
    + + + +    (+) + + + + + + Yes - + + No - [Upload] + + + + + + -- + + + + + + + +
    + +
    + diff --git a/sections/requests/takedelete.php b/sections/requests/takedelete.php new file mode 100644 index 00000000..2609ca46 --- /dev/null +++ b/sections/requests/takedelete.php @@ -0,0 +1,62 @@ +query("SELECT UserID, + Title, + CategoryID, + GroupID + FROM requests + WHERE ID = ".$RequestID); +list($UserID, $Title, $CategoryID, $GroupID) = $DB->next_record(); + +if($LoggedUser['ID'] != $UserID && !check_perms('site_moderate_requests')) { + error(403); +} + +$CategoryName = $Categories[$CategoryID - 1]; + +//Do we need to get artists? +if($CategoryName == "Music") { + $ArtistForm = get_request_artists($RequestID); + $ArtistName = display_artists($ArtistForm, false, true); + $FullName = $ArtistName.$Title; +} else { + $FullName = $Title; +} + + + +// Delete request, votes and tags +$DB->query("DELETE FROM requests WHERE ID='$RequestID'"); +$DB->query("DELETE FROM requests_votes WHERE RequestID='$RequestID'"); +$DB->query("DELETE FROM requests_tags WHERE RequestID='$RequestID'"); +$DB->query("SELECT ArtistID FROM requests_artists WHERE RequestID = ".$RequestID); +$RequestArtists = $DB->to_array(); +foreach($RequestArtists as $RequestArtist) { + $Cache->delete_value('artists_requests_'.$RequestArtist); +} +$DB->query("DELETE FROM requests_artists WHERE RequestID='$RequestID'"); + +if($UserID != $LoggedUser['ID']) { + send_pm($UserID, 0, db_string("A request you created has been deleted"), db_string("The request '".$FullName."' was deleted by [url=http://".NONSSL_SITE_URL."/user.php?id=".$LoggedUser['ID']."]".$LoggedUser['Username']."[/url] for the reason: ".$_POST['reason'])); +} + +write_log("Request $RequestID ($FullName) was deleted by user ".$LoggedUser['ID']." (".$LoggedUser['Username'].") for the reason: ".$_POST['reason']); + +$Cache->delete_value('request_'.$RequestID); +$Cache->delete_value('request_votes_'.$RequestID); +if ($GroupID) { + $Cache->delete_value('requests_group_'.$GroupID); +} +update_sphinx_requests($RequestID); + +header('Location: requests.php'); +?> diff --git a/sections/requests/takefill.php b/sections/requests/takefill.php new file mode 100644 index 00000000..7219d386 --- /dev/null +++ b/sections/requests/takefill.php @@ -0,0 +1,215 @@ +query("SELECT t.UserID, + t.Time, + tg.ReleaseType, + t.Encoding, + t.Format, + t.Media, + t.HasLog, + t.HasCue, + t.LogScore, + tg.CategoryID, + IF(t.Remastered = '1', t.RemasterCatalogueNumber, tg.CatalogueNumber) + FROM torrents AS t + LEFT JOIN torrents_group AS tg ON t.GroupID=tg.ID + WHERE t.ID = ".$TorrentID." + LIMIT 1"); + + +if($DB->record_count() < 1) { + error(404); +} +list($UploaderID, $UploadTime, $TorrentReleaseType, $Bitrate, $Format, $Media, $HasLog, $HasCue, $LogScore, $TorrentCategoryID, $TorrentCatalogueNumber) = $DB->next_record(); + +$FillerID = $LoggedUser['ID']; +$FillerUsername = $LoggedUser['Username']; + +if(!empty($_POST['user']) && check_perms('site_moderate_requests')) { + $FillerUsername = $_POST['user']; + $DB->query("SELECT ID FROM users_main WHERE Username LIKE '".db_string($FillerUsername)."'"); + if($DB->record_count() < 1) { + $Err = "No such user to fill for!"; + } else { + list($FillerID) = $DB->next_record(); + } +} + +if(time_ago($UploadTime) < 3600 && $UploaderID != $FillerID && !check_perms('site_moderate_requests')) { + $Err = "There is a one hour grace period for new uploads, to allow the torrent's uploader to fill the request"; +} + + + +$DB->query("SELECT + Title, + UserID, + TorrentID, + CategoryID, + ReleaseType, + CatalogueNumber, + BitrateList, + FormatList, + MediaList, + LogCue + FROM requests + WHERE ID = ".$RequestID); +list($Title, $RequesterID, $OldTorrentID, $RequestCategoryID, $RequestReleaseType, $RequestCatalogueNumber, $BitrateList, $FormatList, $MediaList, $LogCue) = $DB->next_record(); + + +if(!empty($OldTorrentID)) { + $Err = "This request has already been filled"; +} +if($RequestCategoryID != 0 && $TorrentCategoryID != $RequestCategoryID) { + $Err = "This torrent is of a different category than the request"; +} + +$CategoryName = $Categories[$RequestCategoryID - 1]; + +if($CategoryName == "Music") { + //Commenting out as it's causing some issues with some users being unable to fill, unsure what it is, etc + /*if($RequestCatalogueNumber) { + if($TorrentCatalogueNumber != $RequestCatalogueNumber) { + $Err = "This request requires the catalogue number ".$RequestCatalogueNumber; + } + }*/ + + //WEB has no ripping log. Ditto Vinyl - Actually ditto everything but CD + //$WEBOverride = ((strpos($MediaList, "WEB") !== false) && $Media == "WEB"); + //$VinylOverride = ((strpos($MediaList, "Vinyl") !== false) && $Media == "Vinyl"); + //if($Format == "FLAC" && $LogCue && !$WEBOverride && !$VinylOverride) { + if($Format == "FLAC" && $LogCue && $Media == 'CD') { + if(strpos($LogCue, "Log") && !$HasLog) { + $Err = "This request requires a log"; + } + + /* + * Removed due to rule 2.2.15.6 rendering some requests unfillable + */ + + //if(strpos($LogCue, "Cue") && !$HasCue) { + // $Err = "This request requires a cue"; + //} + + if(strpos($LogCue, "%")) { + preg_match("/\d+/", $LogCue, $Matches); + if((int) $LogScore < (int) $Matches[0]) { + $Err = "This torrent's log score is too low"; + } + } + } + + if ($BitrateList === "Other") { + if ($Bitrate === "Lossless" || $Bitrate === "APS (VBR)" || $Bitrate === "V2 (VBR)" || $Bitrate === "V1 (VBR)" || $Bitrate === "256" || $Bitrate === "APX (VBR)" || $Bitrate === "V0 (VBR)" || $Bitrate === "q8.x (VBR)" || $Bitrate === "320" || $Bitrate === "24bit Lossless") + $Err = $Bitrate." is not allowed bitrate for this request"; + } else if($BitrateList && $BitrateList != "Any") { + if(strpos($BitrateList, $Bitrate) === false) { + $Err = $Bitrate." is not an allowed bitrate for this request"; + } + } + if($FormatList && $FormatList != "Any") { + if(strpos($FormatList, $Format) === false) { + $Err = $Format." is not an allowed format for this request"; + } + } + if($MediaList && $MediaList != "Any") { + if(strpos($MediaList, $Media) === false) { + $Err = $Media." is not allowed media for this request"; + } + } +} + +// Fill request +if(!empty($Err)) { + error($Err); +} + + + +//We're all good! Fill! +$DB->query("UPDATE requests SET + FillerID = ".$FillerID.", + TorrentID = ".$TorrentID.", + TimeFilled = '".sqltime()."' + WHERE ID = ".$RequestID); + +if($CategoryName == "Music") { + $ArtistForm = get_request_artists($RequestID); + $ArtistName = display_artists($ArtistForm, false, true); + $FullName = $ArtistName.$Title; +} else { + $FullName = $Title; +} + +$DB->query("SELECT UserID FROM requests_votes WHERE RequestID = ".$RequestID); +$UserIDs = $DB->to_array(); +foreach ($UserIDs as $User) { + list($VoterID) = $User; + send_pm($VoterID, 0, db_string("The request '".$FullName."' has been filled"), db_string("One of your requests - [url=http://".NONSSL_SITE_URL."/requests.php?action=view&id=".$RequestID."]".$FullName."[/url] - has been filled. You can view it at [url]http://".NONSSL_SITE_URL."/torrents.php?torrentid=".$TorrentID), ''); +} + +$RequestVotes = get_votes_array($RequestID); +write_log("Request ".$RequestID." (".$FullName.") was filled by user ".$FillerID." (".$FillerUsername.") with the torrent ".$TorrentID.", for a ".get_size($RequestVotes['TotalBounty'])." bounty."); + +// Give bounty +$DB->query("UPDATE users_main + SET Uploaded = (Uploaded + ".$RequestVotes['TotalBounty'].") + WHERE ID = ".$FillerID); + + + +$Cache->delete_value('user_stats_'.$FillerID); +$Cache->delete_value('request_'.$RequestID); +if ($GroupID) { + $Cache->delete_value('requests_group_'.$GroupID); +} + + + +$DB->query("SELECT ArtistID FROM requests_artists WHERE RequestID = ".$RequestID); +$ArtistIDs = $DB->to_array(); +foreach($ArtistIDs as $ArtistID) { + $Cache->delete_value('artists_requests_'.$ArtistID); +} + +$SS->UpdateAttributes('requests', array('torrentid','fillerid'), array($RequestID => array((int)$TorrentID,(int)$FillerID))); +update_sphinx_requests($RequestID); + +header('Location: requests.php?action=view&id='.$RequestID); +?> diff --git a/sections/requests/takenew_edit.php b/sections/requests/takenew_edit.php new file mode 100644 index 00000000..885bfefa --- /dev/null +++ b/sections/requests/takenew_edit.php @@ -0,0 +1,539 @@ + 0) { + $Image = trim($_POST['image']); + } else { + $Err = display_str($_POST['image'])." does not appear to be a valid link to an image."; + } +} + +if(empty($_POST['description'])) { + $Err = "You forgot to enter any description!"; +} else { + $Description = trim($_POST['description']); +} + +if($CategoryName == "Music") { + if(empty($_POST['artists'])) { + $Err = "You didn't enter any artists"; + } else { + $Artists = $_POST['artists']; + $Importance = $_POST['importance']; + } + + if(!is_number($_POST['releasetype']) || !array_key_exists($_POST['releasetype'], $ReleaseTypes)) { + $Err = "Please pick a release type"; + } + + $ReleaseType = $_POST['releasetype']; + + if(empty($_POST['all_formats']) && count($_POST['formats']) != count($Formats)) { + $FormatArray = $_POST['formats']; + if(count($FormatArray) < 1) { + $Err = "You must require at least one format"; + } + } else { + $AllFormats = true; + } + + if(empty($_POST['all_bitrates']) && count($_POST['bitrates']) != count($Bitrates)) { + $BitrateArray = $_POST['bitrates']; + if(count($BitrateArray) < 1) { + $Err = "You must require at least one bitrate"; + } + } else { + $AllBitrates = true; + } + + if(empty($_POST['all_media']) && count($_POST['media']) != count($Media)) { + $MediaArray = $_POST['media']; + if(count($MediaArray) < 1) { + $Err = "You must require at least one type of media"; + } + } else { + $AllMedia = true; + } + + //$Bitrates[1] = FLAC + if(!empty($FormatArray) && in_array(1, $FormatArray)) { + $NeedLog = empty($_POST['needlog']) ? false : true; + if($NeedLog) { + if($_POST['minlogscore']) { + $MinLogScore = trim($_POST['minlogscore']); + } else { + $MinLogScore = 0; + } + if(!is_number($MinLogScore)) { + $Err = "You've entered a minimum log score that isn't a number"; + } + } + $NeedCue = empty($_POST['needcue']) ? false : true; + //FLAC was picked, require either Lossless or 24 bit Lossless + if(!$AllBitrates && !in_array(9, $BitrateArray) && !in_array(10, $BitrateArray)) { + $Err = "You selected FLAC as a format but no possible bitrate to fill it (Lossless or 24 bit Lossless)"; + } + + if (($NeedCue || $NeedLog)) { + if (!empty($_POST['all_media']) || $MediaArray[0] != 0) { + $Err = "Only CD is allowed as media for FLAC Log/Cue Requests."; + } + } + } else { + $NeedLog = false; + $NeedCue = false; + $MinLogScore = false; + } + + // GroupID + if (!empty($_POST['groupid'])) { + $GroupID = trim($_POST['groupid']); + $URLRegex = '/^https?:\/\/(www\.|ssl\.)?'.NONSSL_SITE_URL.'\/torrents\.php\?(page=[0-9]+&)?id=([0-9]+)/i'; + if (preg_match($URLRegex, $GroupID, $Matches)) { + $GroupID = $Matches[3]; + } + if (is_number($GroupID)) { + $DB->query("SELECT 1 FROM torrents_group WHERE ID = '$GroupID' AND CategoryID = 1"); + if ($DB->record_count() == 0) { + $Err = "Torrent Group, if entered, must correspond to a music group on the site."; + } + } else { + $Err = "Torrent Group, if entered, must correspond to a music group on the site."; + } + } + + //Not required + if(!empty($_POST['editioninfo'])) { + $EditionInfo = trim($_POST['editioninfo']); + } else { + $EditionInfo = ""; + } + if(!empty($_POST['cataloguenumber'])) { + $CatalogueNumber = trim($_POST['cataloguenumber']); + } else { + $CatalogueNumber = ""; + } + if(!empty($_POST['recordlabel'])) { + $RecordLabel = trim($_POST['recordlabel']); + } else { + $RecordLabel = ""; + } +} + +if($CategoryName == "Music" || $CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + if(empty($_POST['year'])) { + $Err = "You forgot to enter the year!"; + } else { + $Year = trim($_POST['year']); + if(!is_number($Year)) { + $Err = "Your entered year is not a number"; + } + } +} + +//For refilling on error +if($CategoryName == "Music") { + $MainArtistCount = 0; + $ArtistNames = array(); + $ArtistForm = array( + 1 => array(), + 2 => array(), + 3 => array() + ); + for($i = 0, $il = count($Artists); $i < $il; $i++) { + if(trim($Artists[$i]) != "") { + if(!in_array($Artists[$i], $ArtistNames)) { + $ArtistForm[$Importance[$i]][] = array('name' => trim($Artists[$i])); + if(in_array($Importance[$i], array(1,4,5,6))) { + $MainArtistCount++; + } + $ArtistNames[] = trim($Artists[$i]); + } + } + } + if($MainArtistCount < 1) { + $Err = "Please enter at least one main artist, conductor, composer, or DJ"; + } + if(!isset($ArtistNames[0])) { + unset($ArtistForm); + } +} + +if(!empty($Err)) { + error($Err); + $Div = $_POST['unit'] == 'mb' ? 1024*1024 : 1024*1024*1024; + $Bounty /= $Div; + include(SERVER_ROOT.'/sections/requests/new_edit.php'); + die(); +} + +//Databasify the input +if($CategoryName == "Music") { + if(empty($AllBitrates)) { + foreach($BitrateArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Bitrates)) { + $BitrateArray[$Index] = $Bitrates[$MasterIndex]; + } else { + //Hax + error(0); + } + } + $BitrateList = implode("|", $BitrateArray); + } else { + $BitrateList = "Any"; + } + + if(empty($AllFormats)) { + foreach($FormatArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Formats)) { + $FormatArray[$Index] = $Formats[$MasterIndex]; + } else { + //Hax + error(0); + } + } + $FormatList = implode("|", $FormatArray); + } else { + $FormatList = "Any"; + } + + if(empty($AllMedia)) { + foreach($MediaArray as $Index => $MasterIndex) { + if(array_key_exists($Index, $Media)) { + $MediaArray[$Index] = $Media[$MasterIndex]; + } else { + //Hax + error(0); + } + } + $MediaList = implode("|", $MediaArray); + } else { + $MediaList = "Any"; + } + + $LogCue = ""; + if($NeedLog) { + $LogCue .= "Log"; + if($MinLogScore > 0) { + if($MinLogScore >= 100) { + $LogCue .= " (100%)"; + } else { + $LogCue .= " (>= ".$MinLogScore."%)"; + } + } + } + if($NeedCue) { + if($LogCue != "") { + $LogCue .= " + Cue"; + } else { + $LogCue = "Cue"; + } + } +} + +//Query time! +if($CategoryName == "Music") { + if($NewRequest) { + $DB->query("INSERT INTO requests ( + UserID, TimeAdded, LastVote, CategoryID, Title, Year, Image, Description, RecordLabel, + CatalogueNumber, ReleaseType, BitrateList, FormatList, MediaList, LogCue, Visible, GroupID) + VALUES + (".$LoggedUser['ID'].", '".sqltime()."', '".sqltime()."', ".$CategoryID.", '".db_string($Title)."', ".$Year.", '".db_string($Image)."', '".db_string($Description)."','".db_string($RecordLabel)."', + '".db_string($CatalogueNumber)."', ".$ReleaseType.", '".$BitrateList."','".$FormatList."', '".$MediaList."', '".$LogCue."', '1', '$GroupID')"); + + $RequestID = $DB->inserted_id(); + } else { + $DB->query("UPDATE requests + SET CategoryID = ".$CategoryID.", + Title = '".db_string($Title)."', + Year = ".$Year.", + Image = '".db_string($Image)."', + Description = '".db_string($Description)."', + CatalogueNumber = '".db_string($CatalogueNumber)."', + RecordLabel = '".db_string($RecordLabel)."', + ReleaseType = ".$ReleaseType.", + BitrateList = '".$BitrateList."', + FormatList = '".$FormatList."', + MediaList = '".$MediaList."', + LogCue = '".$LogCue."', + GroupID = '".$GroupID."' + WHERE ID = ".$RequestID); + + //I almost didn't think of this, we need to be able to delete artists / tags + $DB->query("SELECT ArtistID FROM requests_artists WHERE RequestID = ".$RequestID); + $RequestArtists = $DB->to_array(); + foreach($RequestArtists as $RequestArtist) { + $Cache->delete_value('artists_requests_'.$RequestArtist); + } + $DB->query("DELETE FROM requests_artists WHERE RequestID = ".$RequestID); + $Cache->delete_value('request_artists_'.$RequestID); + } + + if ($GroupID) { + $Cache->delete_value('requests_group_'.$GroupID); + } + + /* + * Multiple Artists! + * For the multiple artists system, we have 3 steps: + * 1. See if each artist given already exists and if it does, grab the ID. + * 2. For each artist that didn't exist, create an artist. + * 3. Create a row in the requests_artists table for each artist, based on the ID. + */ + + + foreach($ArtistForm as $Importance => $Artists) { + foreach($Artists as $Num => $Artist) { + //1. See if each artist given already exists and if it does, grab the ID. + $DB->query(" + SELECT + aa.ArtistID, + aa.AliasID, + aa.Redirect + FROM artists_alias AS aa + WHERE aa.Name LIKE '".db_string($Artist['name'])."'"); + + if($DB->record_count() > 0){ + list($ArtistID, $AliasID, $Redirect) = $DB->next_record(); + if($Redirect) { + $AliasID = $Redirect; + } + $ArtistForm[$Importance][$Num] = array('id' => $ArtistID, 'aliasid' => $AliasID, 'name' => $Artist['name']); + $Cache->delete_value('artist_'.$ArtistID); + } else { + //2. For each artist that didn't exist, create an artist. + $DB->query("INSERT INTO artists_group (Name) VALUES ('".db_string($Artist['name'])."')"); + $ArtistID = $DB->inserted_id(); + + $Cache->increment('stats_artist_count'); + + $DB->query("INSERT INTO artists_alias (ArtistID, Name) VALUES (".$ArtistID.", '".db_string($Artist['name'])."')"); + $AliasID = $DB->inserted_id(); + + $ArtistForm[$Importance][$Num] = array('id' => $ArtistID, 'aliasid' => $AliasID, 'name' => $Artist['name']); + } + } + } + + + //3. Create a row in the requests_artists table for each artist, based on the ID. + foreach($ArtistForm as $Importance => $Artists) { + foreach($Artists as $Num => $Artist) { + $DB->query("INSERT IGNORE INTO requests_artists (RequestID, ArtistID, AliasID, Importance) VALUES (".$RequestID.", ".$Artist['id'].", ".$Artist['aliasid'].", '".$Importance."')"); + $Cache->increment('stats_album_count'); + $Cache->delete_value('artists_requests_'.$Artist['id']); + } + } + + //End Music only + +} else { + //Not a music request anymore, delete music only fields. + if(!$NewRequest) { + $DB->query("SELECT ArtistID FROM requests_artists WHERE RequestID = ".$RequestID); + $OldArtists = $DB->collect('ArtistID'); + foreach($OldArtists as $ArtistID) { + if(empty($ArtistID)) { continue; } + //Get a count of how many groups or requests use the artist ID + $DB->query("SELECT COUNT(ag.ArtistID) + FROM artists_group as ag + LEFT JOIN requests_artists AS ra ON ag.ArtistID=ra.ArtistID + WHERE ra.ArtistID IS NOT NULL + AND ag.ArtistID = '$ArtistID'"); + list($ReqCount) = $DB->next_record(); + $DB->query("SELECT COUNT(ag.ArtistID) + FROM artists_group as ag + LEFT JOIN torrents_artists AS ta ON ag.ArtistID=ta.ArtistID + WHERE ta.ArtistID IS NOT NULL + AND ag.ArtistID = '$ArtistID'"); + list($GroupCount) = $DB->next_record(); + if(($ReqCount + $GroupCount) == 0) { + //The only group to use this artist + delete_artist($ArtistID); + } else { + //Not the only group, still need to clear cache + $Cache->delete_value('artist_'.$ArtistID); + $Cache->delete_value('artists_requests_'.$ArtistID); + } + } + $DB->query("DELETE FROM requests_artists WHERE RequestID = ".$RequestID); + } + + if($CategoryName == "Audiobooks" || $CategoryName == "Comedy") { + //These types require a year field. + if($NewRequest) { + $DB->query("INSERT INTO requests ( + UserID, TimeAdded, LastVote, CategoryID, Title, Year, Image, Description, Visible) + VALUES + (".$LoggedUser['ID'].", '".sqltime()."', '".sqltime()."', ".$CategoryID.", '".db_string($Title)."', ".$Year.", '".db_string($Image)."', '".db_string($Description)."', '1')"); + + $RequestID = $DB->inserted_id(); + } else { + $DB->query("UPDATE requests + SET CategoryID = ".$CategoryID.", + Title = '".db_string($Title)."', + Year = ".$Year.", + Image = '".db_string($Image)."', + Description = '".db_string($Description)."' + WHERE ID = ".$RequestID); + } + } else { + if($NewRequest) { + $DB->query("INSERT INTO requests ( + UserID, TimeAdded, LastVote, CategoryID, Title, Image, Description, Visible) + VALUES + (".$LoggedUser['ID'].", '".sqltime()."', '".sqltime()."', ".$CategoryID.", '".db_string($Title)."', '".db_string($Image)."', '".db_string($Description)."', '1')"); + + $RequestID = $DB->inserted_id(); + } else { + $DB->query("UPDATE requests + SET CategoryID = ".$CategoryID.", + Title = '".db_string($Title)."', + Image = '".db_string($Image)."', + Description = '".db_string($Description)."' + WHERE ID = ".$RequestID); + } + } +} + +//Tags +if(!$NewRequest) { + $DB->query("DELETE FROM requests_tags WHERE RequestID = ".$RequestID); +} + +$Tags = array_unique(explode(',', $Tags)); +foreach($Tags as $Index => $Tag) { + $Tag = sanitize_tag($Tag); + $Tags[$Index] = $Tag; //For announce + + $DB->query("INSERT INTO tags + (Name, UserID) + VALUES + ('".$Tag."', ".$LoggedUser['ID'].") + ON DUPLICATE KEY UPDATE Uses=Uses+1"); + + $TagID = $DB->inserted_id(); + + $DB->query("INSERT IGNORE INTO requests_tags + (TagID, RequestID) + VALUES + (".$TagID.", ".$RequestID.")"); +} + +if($NewRequest) { + //Remove the bounty and create the vote + $DB->query("INSERT INTO requests_votes + (RequestID, UserID, Bounty) + VALUES + (".$RequestID.", ".$LoggedUser['ID'].", ".($Bytes * (1 - $RequestTax)).")"); + + $DB->query("UPDATE users_main SET Uploaded = (Uploaded - ".$Bytes.") WHERE ID = ".$LoggedUser['ID']); + $Cache->delete_value('user_stats_'.$LoggedUser['ID']); + + + + if($CategoryName == "Music") { + $Announce = "'".$Title."' - ".display_artists($ArtistForm, false, false)." http://".NONSSL_SITE_URL."/requests.php?action=view&id=".$RequestID." - ".implode(" ", $Tags); + } else { + $Announce = "'".$Title."' - http://".NONSSL_SITE_URL."/requests.php?action=view&id=".$RequestID." - ".implode(" ", $Tags); + } + send_irc('PRIVMSG #'.NONSSL_SITE_URL.'-requests :'.$Announce); + +} else { + $Cache->delete_value('request_'.$RequestID); + $Cache->delete_value('request_artists_'.$RequestID); +} + +update_sphinx_requests($RequestID); + +header('Location: requests.php?action=view&id='.$RequestID); +?> diff --git a/sections/requests/takeunfill.php b/sections/requests/takeunfill.php new file mode 100644 index 00000000..e5287737 --- /dev/null +++ b/sections/requests/takeunfill.php @@ -0,0 +1,84 @@ +query("SELECT + r.CategoryID, + r.UserID, + r.FillerID, + r.Title, + u.Uploaded, + r.GroupID + FROM requests AS r + LEFT JOIN users_main AS u ON u.ID=FillerID + WHERE r.ID= ".$RequestID); +list($CategoryID, $UserID, $FillerID, $Title, $Uploaded, $GroupID) = $DB->next_record(); + +if((($LoggedUser['ID'] != $UserID && $LoggedUser['ID'] != $FillerID) && !check_perms('site_moderate_requests')) || $FillerID == 0) { + error(403); +} + +// Unfill +$DB->query("UPDATE requests SET + TorrentID = 0, + FillerID = 0, + TimeFilled = '0000-00-00 00:00:00', + Visible = 1 + WHERE ID = ".$RequestID); + +$CategoryName = $Categories[$CategoryID - 1]; + +if($CategoryName == "Music") { + $ArtistForm = get_request_artists($RequestID); + $ArtistName = display_artists($ArtistForm, false, true); + $FullName = $ArtistName.$Title; +} else { + $FullName = $Title; +} + +$RequestVotes = get_votes_array($RequestID); + +if ($RequestVotes['TotalBounty'] > $Uploaded) { + // If we can't take it all out of upload, zero that out and add whatever is left as download. + $DB->query("UPDATE users_main SET Uploaded = 0 WHERE ID = ".$FillerID); + $DB->query("UPDATE users_main SET Downloaded = Downloaded + ".($RequestVotes['TotalBounty']-$Uploaded)." WHERE ID = ".$FillerID); +} else { + $DB->query("UPDATE users_main SET Uploaded = Uploaded - ".$RequestVotes['TotalBounty']." WHERE ID = ".$FillerID); +} +send_pm($FillerID, 0, db_string("A request you filled has been unfilled"), db_string("The request '[url=http://".NONSSL_SITE_URL."/requests.php?action=view&id=".$RequestID."]".$FullName."[/url]' was unfilled by [url=http://".NONSSL_SITE_URL."/user.php?id=".$LoggedUser['ID']."]".$LoggedUser['Username']."[/url] for the reason: ".$_POST['reason'])); + +$Cache->delete_value('user_stats_'.$FillerID); + +if($UserID != $LoggedUser['ID']) { + send_pm($UserID, 0, db_string("A request you created has been unfilled"), db_string("The request '[url=http://".NONSSL_SITE_URL."/requests.php?action=view&id=".$RequestID."]".$FullName."[/url]' was unfilled by [url=http://".NONSSL_SITE_URL."/user.php?id=".$LoggedUser['ID']."]".$LoggedUser['Username']."[/url] for the reason: ".$_POST['reason'])); +} + +write_log("Request $RequestID ($FullName), with a ".get_size($RequestVotes['TotalBounty'])." bounty, was un-filled by user ".$LoggedUser['ID']." (".$LoggedUser['Username'].") for the reason: ".$_POST['reason']); + +$Cache->delete_value('request_'.$RequestID); +$Cache->delete_value('request_artists_'.$RequestID); +if ($GroupID) { + $Cache->delete_value('requests_group_'.$GroupID); +} + +update_sphinx_requests($RequestID); + +if(!empty($ArtistForm)) { + foreach($ArtistForm as $ArtistType) { + foreach($ArtistType as $Artist) { + $Cache->delete_value('artist_'.$Artist['id']); + $Cache->delete_value('artists_requests_'.$Artist['id']); + } + } +} + + +header('Location: requests.php?action=view&id='.$RequestID); +?> diff --git a/sections/requests/takevote.php b/sections/requests/takevote.php new file mode 100644 index 00000000..253a88a4 --- /dev/null +++ b/sections/requests/takevote.php @@ -0,0 +1,71 @@ +query('SELECT TorrentID FROM requests WHERE ID='.$RequestID); +list($Filled) = $DB->next_record(); + +if($LoggedUser['BytesUploaded'] >= $Amount && $Filled == 0){ + + // Create vote! + $DB->query("INSERT IGNORE INTO requests_votes + (RequestID, UserID, Bounty) + VALUES + (".$RequestID.", ".$LoggedUser['ID'].", ".$Bounty.")"); + + if($DB->affected_rows() < 1) { + //Insert failed, probably a dupe vote, just increase their bounty. + $DB->query("UPDATE requests_votes + SET Bounty = (Bounty + ".$Bounty.") + WHERE + UserID = ".$LoggedUser['ID']." + AND RequestID = ".$RequestID); + echo 'dupe'; + } + + + + $DB->query("UPDATE requests SET LastVote = NOW() WHERE ID = ".$RequestID); + + $Cache->delete_value('request_'.$RequestID); + $Cache->delete_value('request_votes_'.$RequestID); + + $ArtistForm = get_request_artists($RequestID); + foreach($ArtistForm as $Importance) { + foreach($Importance as $Artist) { + $Cache->delete_value('artists_requests_'.$Artist['id']); + } + } + + // Subtract amount from user + $DB->query("UPDATE users_main SET Uploaded = (Uploaded - ".$Amount.") WHERE ID = ".$LoggedUser['ID']); + $Cache->delete_value('user_stats_'.$LoggedUser['ID']); + + update_sphinx_requests($RequestID); + echo 'success'; +} elseif($LoggedUser['BytesUploaded'] < $Amount) { + echo 'bankrupt'; +} + +?> diff --git a/sections/rules/chat.php b/sections/rules/chat.php new file mode 100644 index 00000000..f0fead3f --- /dev/null +++ b/sections/rules/chat.php @@ -0,0 +1,138 @@ + + +
    +
    +

    Anything not allowed on the forums, is also not allowed on IRC and vice versa. They are separated for convenience only.

    +
    +
    +

    Forum Rules

    +
    +
      +
    • + Many forums (Tutorials, The Library, etc.) have their own set of rules. Make sure you read and take note of these rules before you attempt to post in one of these forums. +
    • +
    • + Don't use all capital letters, excessive !!! (exclamation marks) or ??? (question marks), it seems like you're shouting! +
    • +
    • + No lame referral schemes. This includes freeipods.com, freepsps.com, or any other similar scheme in which the poster gets personal gain from users clicking a link. +
    • +
    • + No asking for money for any reason whatsoever. We don't know or care about your friend who lost everything, or dying relative who wants to enjoy their last few moments alive by being given lots of money. +
    • +
    • + No advertising your uploads. +
    • +
    • + No posting music requests in forums, there's a request link on the top bar, please use that instead. +
    • +
    • + No flaming, be pleasant and polite. Don't use offensive language, and don't be confrontational for the sake of confrontation. +
    • +
    • + Don't point out or attack other members' share ratios. A higher ratio does not make you better than someone else. +
    • +
    • + Try not to ask stupid questions. A stupid question is one that you could have found the answer to yourself with a little research, or one that you're asking in the wrong place. If you do the basic research suggested (i.e., read the rules/wiki) or search the forums and don't find the answer to your question, then go ahead and ask. Staff/FLS are not here to hand-feed you the answers you could have found on your own with a little bit of effort. +
    • +
    • + Be sure you read all the stickies. +
    • +
    • + Use descriptive and specific subject lines. This helps others decide whether your particular words of wisdom relate to a topic they care about. +
    • +
    • + Try not to post comments that don't add anything to the discussion. When you're just cruising through a thread in a leisurely manner, it's not too annoying to read through a lot of "hear, hear"'s and "I agree"'s. But if you're actually trying to find information, it's a pain in the neck. So save those one-word responses for threads that have degenerated to the point where none but true aficionados are following them any more. +

      + Or short: NO spamming +

      +
    • +
    • + Refrain from quoting excessively. When quoting someone, use only the portion of the quote that is absolutely necessary. This includes quoting pictures! +
    • +
    • + No posting of requests for serials or cracks. No links to warez or crack sites in the forums. +
    • +
    • + No political or religious discussions. These types of discussions lead to arguments and flaming users, something that will not be tolerated. The only exception to this rule is The Library forum, which exists solely for the purpose of intellectual discussion and civilized debate. +
    • +
    • + Don't waste other people's bandwidth by posting images of a large file size. +
    • +
    • + Be patient with newcomers. Once you have become an expert, it is easy to forget that you started out as a newbie too. +
    • +
    • + No requesting invites to any sites anywhere on the site or IRC. Invites may be offered in the invite forum, and nowhere else. +
    • +
    • + Do not include pornographic or semi-pornographic material in your posts. +
    • +
    • + No language other than English is permitted in the forums. If we can't understand it, we can't moderate it. +
    • +
    +
    +
    + + + +
    +

    IRC Rules

    +
    +
      +
    • + Staff have the final decision, if they say stop and you continue, expect at least to be banned from the IRC server. +
    • +
    • + Be respectful to IRC Operators and Administrators. These people are site staff who volunteer their time for little compensation. They are there for the benefit of all and to aid in conflict resolution, do not waste their time. +
    • +
    • + Do not link shock sites or anything NSFW (not safe for work) without a warning. If in doubt, ask a staff member in #what.cd-help about it. +
    • +
    • + Excessive swearing will get you kicked, keep swearing to a minimum. +
    • +
    • + Do not leave your Caps Lock on all the time. It gets annoying, and you will likely get yourself kicked. +
    • +
    • + No arguing. You can't win an argument over the internet, so you're just wasting your time trying. +
    • +
    • + No prejudice, especially related to race, religion, politics, ethnic background, etc. It is highly suggested to avoid this entirely. +
    • +
    • + Flooding is irritating and will merit you a kick. This includes but is not limited to: automatic now playing scripts, pasting large amounts of text, and multiple consecutive lines with no relevance to the conversation at hand. +
    • +
    • + Impersonation of other members (particularly staff members) will not go unpunished. If you are uncertain of a user's identity, check their vhost. +
    • +
    • + Spamming is strictly forbidden. This includes but is not limited to: personal sites, online auctions, and torrent uploads. +
    • +
    • + Obsessive annoyance both to other users and staff will not be tolerated. +
    • +
    • + Don't PM, DCC, or Query anyone you don't know or have never talked to without asking, this applies specifically to staff. +
    • +
    • + No language other than English is permitted in the official IRC channels. If we can't understand it, we can't moderate it. +
    • +
    • + The offering, selling, trading and giving away of invites to this or any other site on our IRC network is strictly forbidden. +
    • +
    • + Read the topic before asking questions. +
    • +
    +
    + +
    + diff --git a/sections/rules/clients.php b/sections/rules/clients.php new file mode 100644 index 00000000..1bdc5043 --- /dev/null +++ b/sections/rules/clients.php @@ -0,0 +1,56 @@ +get_value('whitelisted_clients')) { + $DB->query('SELECT vstring FROM xbt_client_whitelist WHERE vstring NOT LIKE \'//%\' ORDER BY vstring ASC'); + $WhitelistedClients = $DB->to_array(false,MYSQLI_NUM,false); + $Cache->cache_value('whitelisted_clients',$WhitelistedClients,604800); +} +?> +
    +

    Client Whitelist

    +
    +

    Client rules are how we maintain the integrity of our swarms. This allows us to filter out disruptive and dishonest clients that may hurt the performance of either the tracker or individual peers.

    + + + + + + + + + + +
    Allowed Client
    +
    + +

    Further Rules

    +
    +

    + The modification of clients to bypass our client requirements (spoofing) is explicitly forbidden. People caught doing this will be instantly and permanently banned. This is your only warning. +

    +

    + The use of clients or proxies which have been modified to report incorrect stats to the tracker (cheating) is not allowed, and will result in a permanent ban. Additionally, your information will be passed on to representatives of other trackers, where you are liable to be banned as well. +

    +

    + The testing of unstable clients by developers is not allowed unless approved by a staff member. +

    +
    +

    Further Details

    +
    +

    + If someone you invited to the site breaks the above rules you will receive a 2 month warning and lose the right to invite people to this site. +

    +

    + If you were invited by someone who broke the above rules, your account will be disabled without warning. +

    +
    + +
    + diff --git a/sections/rules/collages.php b/sections/rules/collages.php new file mode 100644 index 00000000..b430a83e --- /dev/null +++ b/sections/rules/collages.php @@ -0,0 +1,57 @@ + +
    +

    Collages

    +
    +
      +
    • Collages in the Discography, Staff Picks, Label, and Charts categories must be based on fact, and not opinion. If something is a published Best Of (for instance, "Pitchfork's Best Albums of the 1990's") then it should go in the Charts category.
    • + +
    • + Collages in the Personal, Theme, and Genre Introductions categories may be based on opinion. You must respect others' opinions whilst creating and populating Theme and Genre Introduction collages. +
    • +
    • + Vandalizing of collages will be taken very seriously, resulting in collage editing privileges being removed (at a minimum). +
    • +
    • + Personal Best Of collages are only allowed in the new Personal Collages category. You must be a Power User+ or Donor to create one. +
    • +
    • + A well-defined group of people, for instance Torrent Masters, or Interviewers, may create a Group Picks Theme collage with one pick per person, after having gained permission for the collage from Staff. +
    • +
    • + There may only be one collage per Genre Introduction/Theme. Dupe collages will be deleted. +
    • +
    • + Theme/Genre Introduction collages must be sensible, and reasonably broad. Those that do not fit this description will be deleted. +
    • +
    • + Collages are not an alternative to the tagging system. A collage such as 'mathcore torrents' wouldn't be allowed, because it is far more appropriate to just tag the torrents as mathcore. Of course, an 'xysite.com worst 50 mathcore albums' collage would be looked upon differently. +
    • +
    • + Collages should not be used to create artist discographies, as the artist pages already exist for this purpose. However, for an artist who has a multitude of side projects, it is allowed to create a collage containing all of the projects, to be placed in the Discography category. +
    • +
    • + Power Users and Donors get one personal collage. Elites can have two, Torrent Masters can have up to three, Power TMs up to four and Elite TM+ up to five. Donors always receive one more than the class maximum. +
    • +
    • + Every collage must have at least 3 albums in it. +
    • +
    • + Please check to see that a similar collage does not already exist. If a similar collage does exist, please contribute to the existing collage. +
    • +
    • + Please give your collage an appropriate title and a decent description explaining its purpose. +
    • +
    • + Please attempt to add album art to every torrent in your collage. +
    • + +
    +
    + +
    + diff --git a/sections/rules/index.php b/sections/rules/index.php new file mode 100644 index 00000000..34cf0736 --- /dev/null +++ b/sections/rules/index.php @@ -0,0 +1,32 @@ + +

    Other Sections

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CategoryAdditional Info
    + Golden Rules + + These are the most important rules, breaking these will result in the most serious consequences. +
    + Ratio + + These are the rules for seeding/leeching activity on this site. +
    + Requests + + These are the rules that govern requests. +
    + Collages + + These are the rules that govern collages. +
    + Clients + + These are the clients we allow to connect to our tracker and rules specific to them. +
    + Upload + + This is the section of the rules regarding any and all content which is allowed on this site. +
    + Chat + + Read this before posting in our forums or talking on the IRC. +
    + Tagging + + These rules govern what tags can and can not be added. +
    Other Languages (Please note, these are community maintained and subject to error.)
    + Français + + Les règles en français. +
    + Svenska + + Svenska Regler +
    + Deutsch + + Die Regeln auf Deutsch +
    + Español + + Las reglas en español +
    +
    + diff --git a/sections/rules/ratio.php b/sections/rules/ratio.php new file mode 100644 index 00000000..921af897 --- /dev/null +++ b/sections/rules/ratio.php @@ -0,0 +1,148 @@ + +
    +

    Ratio Rules

    +
    +

    + Your ratio is the amount you've uploaded divided by the amount you've downloaded. +

    +

    + To maintain leeching privileges, we require that you maintain a ratio above a minimum ratio. This is called your "required ratio". If your upload/download ratio goes below your required ratio, your account will be given a two week period to fix it before you lose your ability to download. This is called "ratio watch". +

    + +

    + The required ratio is NOT the extra amount of ratio you need to gain. It is the minimum required ratio you must maintain. +

    + +

    + Your required ratio is unique, and is calculated from the amount you've downloaded, and the percentage of your snatched torrents which you are still seeding. +

    + +

    + It is not necessary to know how this ratio is calculated. What you need to know is that downloading makes the required ratio go up (bad) and seeding your snatches forever makes your required ratio go down (good). You can view your required ratio in the site header (it is the "Required" value). You want a high ratio, and a low required ratio. +

    + +

    + The exact formula for calculating the required ratio is provided merely for the curious. It is done in three steps. +

    + +

    + The first step is by determining how high and how low your required ratio can be. This is determined by looking up how much you've downloaded from the following table: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Amount downloadedRequired ratio (0% seeded)Required ratio (100% seeded)
    0-5GB0.000.00
    5-10GB0.150.00
    10-20GB0.200.00
    20-30GB0.300.05
    30-40GB0.400.10
    40-50GB0.500.20
    50-60GB0.600.30
    60-80GB0.600.40
    80-100GB0.600.50
    100+GB0.600.60
    + +

    + So for example, if you've downloaded 25GB, your required ratio will be somewhere between 0.05 and 0.30. +

    + +

    + To get this range of requirements to a more precise number, what we do is take the required ratio (0% seeded) for your download band, multiply it by , and round it up to the required ratio (100% seeded) if need be. Therefore, your required ratio will always lie between the 0% seeded and 100% seeded requirements, depending on the percentage of torrents you are seeding. +

    + +

    + In the formula, "snatched" is the number of non-deleted unique snatches (complete downloads) you have made (so if you snatch a torrent twice, it only counts once, and if it is then deleted, it's not counted at all). "Seeding" is the average number of torrents you've seeded over at least 72 hours in the past week. If you've seeded less than 72 hours in the past week, the "seeding" value will go down (which is bad). +

    + +

    + Thus, if you have downloaded less than 20GB, and you are seeding 100% of your snatches, you will have no required ratio. If you have downloaded less than 5GB, then no matter what percentage of snatches you are seeding, you will again have no required ratio. +

    + +

    + If you stop seeding for an entire week, your required ratio will be the "required ratio (0% seeded)" for your download band. Your required ratio will go down once you start seeding again. +

    + +

    + Take note how, as your download increases, the 0% seeded and 100% seeded required ratios begin to taper together. They meet at 100GB of download, meaning that after you've downloaded 100GB, your ratio requirement will be 0.60, no matter what percentage of your snatches you're seeding. +

    + +

    Important information you should know

    + +

    + If your ratio does not meet your required ratio, you will be put on ratio watch. You will have two weeks to get your ratio above your required ratio - failure to do so will result in your downloading privileges being automatically disabled. +

    + +

    + If you download over 10GB while you're on ratio watch, you will be instantly disabled. +

    + +

    + Everyone gets to download their first 5GB before ratio watch kicks in. +

    + +

    + To get out of ratio watch, you must either raise your ratio by uploading more, or lower your required ratio by seeding more. Your ratio MUST be above your required ratio. +

    + +

    + If you have lost your downloading privileges, your new required ratio will be the 0% seeded ratio. You will re-gain your downloading privileges once your ratio is above that required ratio. +

    + +

    + The ratio watch system is completely automatic, and cannot be altered by staff. +

    + +
    + +
    + diff --git a/sections/rules/requests.php b/sections/rules/requests.php new file mode 100644 index 00000000..84a826b0 --- /dev/null +++ b/sections/rules/requests.php @@ -0,0 +1,30 @@ + +
    +

    Requests

    +
    +
      +
    • + Do not make requests for torrents that break the rules. It is your responsibility that the request follows the rules. Your request will be deleted and you will not get your bounty back. Requests cannot be more specific than the upload (and trumping) rules. For example, requesting an MP3 torrent with a log when the rules prohibit replacing an MP3 torrent without a log. Such a request asks for a duplicate to be uploaded. Exceptions: Requests made before the November 2008 rule change are not subject to deletion. However, you are advised to edit such older requests to comply with the rules. +
    • +
    • + Only one title (application, album, ...) per request. No requests for multiple albums (discographies) or vague requirements. You may ask for multiple formats, but you cannot specify all of them. For example, you may ask for either a FLAC or V0, but not both formats. You may also make a list of albums by one artist that satisfies your request, but the request can be filled with only one album. Application requests can consist of only one application, but may span a range of different versions. However, such requests can be filled with only one version of that title. +
    • +
    • + Do not unfill requests for trivial reasons. If you did not specify in your request what you wanted (such as bitrates or a particular edition), do not unfill and later change the description. Do not unfill requests if you are unsure of what you are doing (e.g. the filled torrent may be a transcode, but you don't know how to tell). Ask for help from staff in that case. You may unfill if the torrent doesn't fit your specifications stated clearly in the request. +
    • +
    • + All users must have an equal chance to fill a request. Trading upload credit is not allowed. Abusing the request system to exchange favors for other users is not tolerated. That includes making specific requests for certain users (whether explicitly named or not). Making requests for releases, and then unfilling so that one particular user can fill the request is not allowed. If reported, both the requester and user filling the request will receive a warning and lose the request bounty. +
    • +
    • + No manipulation of the requester for bounty. The bounty is a reward for helping other users—it should not be a ransom. Any user who refuses to fill a request unless the bounty is increased will face harsh punishment. +
    • +
    +
    + +
    + diff --git a/sections/rules/rules.php b/sections/rules/rules.php new file mode 100644 index 00000000..78281b22 --- /dev/null +++ b/sections/rules/rules.php @@ -0,0 +1,65 @@ + + +
    +

    Golden Rules

    +
    +
      +
    • + All staff decisions must be respected. If you take issue with a decision, you must do so privately with the staff member who issued the decision or with an administrator of the site. Complaining about staff decisions in public or otherwise disrespecting staff members will not be taken lightly. +
    • +
    • + Access to this website is a privilege, not a right, and it can be taken away from you for any reason. +
    • +
    • + One account per person per lifetime. Anyone creating additional accounts will be banned. +
    • +
    • + Avatars must not exceed 256kB or be vertically longer than 400px. Avatars must be safe for work, be entirely unoffensive and not contain any nudity or religious imagery. Use common sense. +
    • +
    • + Do not post our .torrent files on other sites. Every .torrent file has your personal passkey embedded in it. The tracker will automatically disable your account if you share your torrent files with others. You will not get your account back. This doesn't prohibit you sharing the content on other sites, just the .torrent file. +
    • +
    • + Any torrent you are seeding to this tracker must only have our tracker's URL in it. Adding another tracker's URL will cause incorrect data to be sent to our tracker, and will lead to you getting disabled for cheating. +
    • +
    • + This is a torrent site which promotes sharing amongst the community. If you are not willing to give back to the community what you take from it, this site is not for you. In other words, we expect you to have an acceptable share ratio. If you download a torrent, please, seed the copy you have until there are sufficient people seeding as well before you stop. +
    • +
    • + Do not browse the site using proxies or TOR. The site will automatically alert us. This includes VPNs with dynamic IP addresses. +
    • +
    • + Asking for invites to any site is not allowed anywhere on What.CD or our IRC network. Invites may be offered in the Invites forum, and nowhere else. +
    • +
    • + Trading and selling invites is strictly prohibited, as is offering them in public - this includes on any forum which is not a class-restricted section on an invitation-only torrent site. +
    • +
    • + Trading, selling, sharing, or giving away your account is prohibited as well. PM a mod to disable you if you no longer want it. +
    • +
    • + You're completely responsible for the people you invite. If your invitees are caught cheating or trading/selling invites, not only will they be banned, so will you. Be careful who you invite. Invites are a precious commodity. +
    • +
    • + Be careful when sharing an IP or a computer with a friend if they have (or have had) an account. From then on your accounts will be inherently linked and if one of you violates the rules, both accounts will be disabled along with any other accounts linked by IP. This rule applies to logging into the site. +
    • +
    • + Attempting to find or exploit a bug in the site code is the worst possible offense you can commit. We have automatic systems in place for monitoring these activities, and committing them will result in the banning of you, your inviter, and your inviter's entire invite tree. +
    • +
    • + We're a community. Working together is what makes this place what it is. There are well over a thousand new torrents uploaded every day and sadly the staff aren't psychic. If you come across something which violates a rule, report it! Ignoring it is only damaging the community. +
    • +
    • + We respect the wishes of other sites here, as we wish for them to do the same. Please refrain from posting links or full names of sites that want not to be mentioned. +
    • +
    +
    + + +
    + diff --git a/sections/rules/tag.php b/sections/rules/tag.php new file mode 100644 index 00000000..a55d67de --- /dev/null +++ b/sections/rules/tag.php @@ -0,0 +1,29 @@ + + +
    +

    Tagging rules

    +
    +
      +
    • Tags should be comma separated, and you should use a period ('.') to separate words inside a tag - eg. 'hip.hop'. +
    • + There is a list of official tags on upload.php. Please use these tags instead of 'unofficial' tags (eg. use the official 'drum.and.bass' tag, instead of an unofficial 'dnb' tag.) +
    • + Avoid abbreviations if at all possible. So instead of tagging an album as 'alt', tag it as 'alternative'. Make sure that you use correct spelling. +
    • + Avoid using multiple synonymous tags. Using both 'prog.rock' and 'progressive.rock' is redundant and annoying - just use the official 'progressive.rock' tag. +
    • + Don't use 'useless' tags, such as 'seen.live', 'awesome', 'rap' (is encompassed by 'hip.hop'), etc. If an album is live, you can tag it as 'live'. +
    • + Only tag information on the album itself - NOT THE INDIVIDUAL RELEASE. Tags such as 'v0', 'eac', 'vinyl', 'from.oink' etc are strictly forbidden. Remember that these tags will be used for other versions of the same album. +
    • +
    +
    + + +
    + \ No newline at end of file diff --git a/sections/rules/upload.php b/sections/rules/upload.php new file mode 100644 index 00000000..b8aecb5c --- /dev/null +++ b/sections/rules/upload.php @@ -0,0 +1,691 @@ + + + + +
    + + + Example: The search term FLAC returns all rules containing FLAC. The search term FLAC+trump returns all rules containing both FLAC and trump. +
    + + +
    +
    +

    Introduction

    +
    +

    The upload rules below appear overwhelmingly long and detailed at first glance. However, the length is for explaining the rules clearly and thoroughly. A summary of each rule is in bold text before the actual rule for easier reading. You may also find the corresponding rule sections in the Index. The corresponding (move one level up) and rule section links (move down into the document) help provide quick navigation.

    +

    If you are still unsure of what a rule means before uploading something, PLEASE ask at any of the following forms of site user support: First-Line Support, The Help Forum, #what.cd-help on IRC. Privately message a moderator on the site if other support has directed you to a moderator for resolution or support has been unhelpful in your case. If you find any dead links in the upload rules, let a staff member know so it can be promptly fixed.

    + +
    +
    + +

    1. Uploading Rules

    + +
    1.1. General
    +
    +
      +
    • ↑_ 1.1.1. Only music, applications, comic books, eBooks, comedy (audio), audiobooks, and eLearning videos are allowed here. + +
    • +
    • ↑_ 1.1.2. Duplicate torrents in any category are not allowed. There are some exceptions to this rule, which are outlined in their relevant sections below. +
    • +
    • ↑_ 1.1.3. No freely available content in non-music sections. If you could just download from the web, so can everyone else. Each main section explains in greater detail what "freely available" means in context. See 2.1.9 in regards to freely available music. +
    • + +
    • ↑_ 1.1.4. Seed complete copies. Do not upload a torrent unless you intend to seed until there are at least 1.0 distributed copies. Seeding past this minimum is strongly encouraged. +
    • +
    • ↑_ 1.1.5. No advertisements. Do not advertise other sites in your torrent descriptions, torrent directories, or the contents of your torrent. We have no advertising and neither should you. Exceptions: Additional information about an artist, album, or band is acceptable, and does not count as advertising. +
    • + +
    • ↑_ 1.1.6. Archived files in uploads are not allowed. Exceptions: The sections that allow archived files (e.g. zip, rar, iso, etc.) are the following: +
        +
      • Comic Books (.cbr and .cbz).
      • +
      • Scene released torrents in non-music categories.
      • +
      • eBooks and sheet music may be individually archived.
      • + +
      +
    • +
    +
    + +
    1.2. Specifically Banned
    +
    +
      +
    • ↑_ 1.2.1. Anything not specifically allowed below. If you have any doubts, ask before uploading. +
    • + +
    • ↑_ 1.2.2. Any car parts and car data programs. This ban includes programs like AllData and vendor-specific diagnostic programs such as Carsoft. +
    • +
    • ↑_ 1.2.3. Videos of any kind (other than eLearning Videos). No movies, no TV shows, no concerts, and no data/video tracks from enhanced CDs. +
    • +
    • ↑_ 1.2.4. Pornography or nudity of any kind. This ban includes pictures, erotic comic books or hentai, sex manuals, erotic magazines, etc. +
    • + +
    • ↑_ 1.2.5. Games of any kind. No games of any kind are allowed: whether PC, Mac, phone or any other platform. +
    • +
    • ↑_ 1.2.6. Collections of pictures or wallpapers are not applications. You may not upload them to any category. +
    • +
    • ↑_ 1.2.7. User compilations in any category. All "packs" must be reasonably official as specified in each category. +
    • + +
    • ↑_ 1.2.8. DRM-restricted files: files must not be encrypted or in a restricted format that impedes sharing. It is also highly encouraged that you remove personal information from non-DRM protected files (such as iTunes Plus releases). +
    • +
    +
    + +
    1.3. Scene Uploads
    +
    + +
      +
    • ↑_ 1.3.1. Do not add irrelevant credits to your torrent. Your name is credited to the upload, and there's no need to plaster it all over the place! +
    • +
    • ↑_ 1.3.2. You may give credit to the release group (optional). If you really want to give credit to the release group, mention the full release name, including group name in the Release description section. +
    • + +
    • ↑_ 1.3.3. No NFO art pasted in the album description. Unedited NFOs are allowed within the specific Release description–not the Album description. If you must include some information from the NFO in the Album description or torrent description, include only the tracklist, album notes, and other essential information. Specific encoding settings belong in the Release description. +
    • + +
    • ↑_ 1.3.4. Use the correct actual album title on the upload page; do not use the scene-given title. Naming your albums_titles_like_this or your.albums.like.this is not allowed. Use the actual release title and artist. Do not use the title from the folder or NFO of the scene release. +
    • +
    • ↑_ 1.3.5. Scene releases must be complete (as released) to use the scene label. If you've changed the tags, unpacked the archive, removed any files, split the tracks, or altered the naming, then it is no longer a scene release. It should not be labeled as such. +
    • + +
    • ↑_ 1.3.6. No protected archives. Archived releases must not be password protected. +
    • +
    • ↑_ 1.3.7. Scene releases must conform to rules specified for their respective section. For example, music scene releases must adhere to the music quality and formatting rules no matter how the original files were released. If the scene archives were password protected, you cannot upload them to this site unmodified. Exceptions: You may upload scene releases that originally do not fit in the rules if you can make the necessary changes within the rules. However, these modified uploads must not be labeled as "scene." +
    • + +
    +
    + +

    2. Music

    + +
    2.1. General
    +
    +
      +
    • ↑_ 2.1.1. The only formats allowed for music consist of the following lossy and lossless formats: +
        +
      • Lossy: MP3, Ogg Vorbis, AAC, AC3, DTS
      • +
      • Lossless: FLAC
      • +
      +

      Only standard versions of each format are allowed. Hybrid formats that combine both lossless and lossy audio data such as DTS-HD and mp3HD are not allowed. AC3 and DTS are reserved for commercial media sources only if they contain such tracks; transcoding from any other source, including lossless (e.g. PCM and MLP formats), is not allowed.

      +
    • +
    • ↑_ 2.1.2. No transcodes or re-encodes of lossy releases are acceptable here. There are no exceptions regardless of how rare you claim the release is. The only acceptable transcodes are releases that were transcoded from a lossless source (e.g. CD, SBD, DAT, Vinyl, SACD, LPCM). Exceptions: Official lossy-mastered releases are not considered to be transcodes. They are allowed on the site. It is highly recommended you provide proof in at least one of the following forms: a) digital photo proving ownership of the CD or hi-res scan of the CD top b) a rip log c) confidence of 2 or more verification with AccurateRip in the rip log or after ripping (with arcue.pl / arcue.exe, CUE Tools, or equivalent) in your Release description. You must provide this proof if requested by staff. +
    • + +
    • ↑_ 2.1.3. Music releases must have an average bitrate of at least 192kbps regardless of the format. Exceptions: The following VBR encodes may go under the 192kbps limit: LAME -V2, -V1, -V0, APS, APX, MP3 192 (VBR), Ogg Vorbis -q8 (~256 VBR), and AAC ~192 (VBR) to AAC ~256 (VBR) releases. +
        +
      • Recommendations for MP3 encoding: We strongly encourage the latest Hydrogenaudio recommended stable release of LAME (currently 3.98.4) for MP3 encoding. You can find out more information about LAME and its options at the Hydrogenaudio Wiki. +
      • +
      • Recommendations for Ogg Vorbis encoding: We strongly encourage the use of newer and well-maintained Ogg Vorbis encoders such as Aoyumi's aoTuV series of encoders. However, as long as the encoder satiates the requirements for Ogg Vorbis presets and average bitrates on this site, you may use any encoder you prefer. For more information on aoTuV and other Ogg Vorbis encoders, read the wiki page at Hydrogenaudio. +
      • + +
      • Recommendations for AAC encoding: Encoding object types LC/Low Complexity and HE/High Efficiency are strongly encouraged. LC/Low Complexity is recommended for music uploads. HE/High Efficiency is optimized for lower bitrates, which makes it ideal for comedy or audio books. You may use other encoding profiles and object types, but they will not be compatible on most portable players, media players, and systems. Find out more information here. +
      • +
      +
    • +
    • ↑_ 2.1.4. Bitrates must accurately reflect encoder presets or average bitrate of the audio files. You are responsible for supplying correct format and bitrate information on the upload page. All audio torrents must have accurate labeling for the encoder settings used or the average bitrate. This means that lossy formats such as MP3, AAC, DTS, and Ogg Vorbis cannot have a bitrate of "lossless." Conversely, FLAC cannot have fixed bitrates or xxx(VBR) bitrates. Non-LAME formats and MP3 encoders cannot use LAME's VBR switches (-V0, -V1, -V2, etc). If you are uploading a non-LAME MP3, determine the average bitrate of the files. Then select "Other" for bitrate and type in xxx (VBR) where "xxx" is the bitrate you found. Some tools to determine the bitrates of audio files are Audio Identifier, Mr. Questionman (mirror), or Dnuos. If the bitrate is labeled incorrectly on your torrent, your torrent may be deleted if reported. +
    • + +
    • ↑_ 2.1.5. Albums must not be ripped or uploaded as a single track. If the tracks on the original CD were separate, you must rip them to separate files. Clearly, CDs with single tracks are permitted to be uploaded without prior splitting. You are encouraged to use MusiCutter or MP3DirectCut for MP3 and CUE Tools, XLD, or EAC for lossless if you need to split up an album image into individual tracks. Exceptions: Gapless DJ or professional mixes released as MP3+CUE images are allowed as unseparated album images on the site. This includes scene DJ mixes. No other format is allowed in this unsplit form. Unsplit MP3 albums containing separate tracks are not allowed if missing a cue sheet. +
    • + +
    • ↑_ 2.1.6. All music torrents must be encoded with a single encoder using the same settings. This means you cannot create a torrent which contains both CBR and VBR files, nor can you upload torrents containing a mix of APS (VBR)/-V2 (VBR) and APX (VBR)/-V0 (VBR). Including other kinds of audio quality, such as duplicate lossy files in a lossless torrent is also prohibited. This kind of release is referred to as a "mutt rip." +
    • +
    • ↑_ 2.1.7. Use only the allowed container formats for audio files. Use .m4a and .mp4 for AAC, and .ogg for Vorbis only. All other formats should not be encapsulated in containers. (e.g. FLAC must not be in an Ogg container, MP3 must not be in an .m4a container, and so forth.) Exceptions: DTS CD-sourced audio rips, although contained in WAV, should have the .dts extension. +
    • + +
    • ↑_ 2.1.8. Music not sourced from vinyl must not contain pops, clicks, or skips. They will be deleted for rip/encode errors if reported. Music that is sourced from vinyl must not have excessive problems. +
    • +
    • ↑_ 2.1.9. Freely available music is allowed. Music uploaded may be freely available on the web (come from official sources such as record label, band websites, or the Internet Archive). Uploads can come from other torrent sites, but you take responsibility for determining the music is not transcoded. You are highly encouraged to include a link to the original host site or a note about the source for freely available files. However, this is not required and not grounds for reporting a torrent if missing such a link. All freely available music must conform to quality rules and formatting rules. This means it must be tagged correctly, not be a transcode, be separate tracks, and so forth. Freely available music uploads should have the "WEB" media format if no other source media (e.g. CD, DVD, etc.) can be established for the files. +
    • + +
    • ↑_ 2.1.10. Label water-marked or voice-over releases clearly. Watermarks or voice-overs must be clearly indicated in the torrent description. The torrent will be deleted for quality misrepresentation if not noted. +
    • +
    • ↑_ 2.1.11. Radio, television, web rips and podcasts are not allowed. It does not matter whether it's FM, direct satellite, internet, or even if it's a pre-broadcast tape. It's too difficult for staff to moderate such things. Radio does not have enough bandwidth to meet our 192kbps rule. Anything on the radio has already gone through several conversions or re-encodes. Note: Do not confuse web rips for WEB. The "WEB" media label on the upload page is for digital downloads, and has nothing to do with web rips. + +
    • +
    • ↑_ 2.1.12. No unofficial audience recordings. Unofficially-mastered audience recordings (AUD) are not allowed here regardless of how rare you think they are. These include recordings on bootleg labels and those mastered by fans or traders. Unofficial IEM (In Ear Monitor), ALD (Assistive Listening Device), Mini-Disc, and Matrix-sourced recordings are also not allowed. None of those are pure soundboard quality either. Exceptions: Officially-remastered AUD/IEM/ALD/Mini-Disc/Matrix recordings are allowed. These may be re-appropriated recordings released with the artist's or their label's consent. Bonus tracks from such recording sources are also exempt since the tracks are released officially with the album. +
    • +
    • ↑_ 2.1.13. Tape (VHS, Video-8, etc.) music sources are not suitable for this site. The frequency range is not good enough to meet the high quality we strive to maintain here. Hi-fi formats of tapes, such as Hi-Fi VHS, have good frequency range above regular standards (near CD quality at times). However, none of these sources are allowed on the site for moderation reasons. +
    • + +
    • ↑_ 2.1.14. Cassettes are allowed under strict conditions. Rare releases available only on cassette may be uploaded under strict special conditions. Cassette-sourced uploads must be approved by staff first. You must contact a moderator privately for approval before uploading. Include proof in the form of discography information from a reputable source as well as spectrals of 2 songs in your message. Staff reserves the right to refuse any badly-done cassette rips. Staff will immediately reject any cassette sources with poor lineage such as Audience recordings, bootlegs, or multi-generational rips. Unapproved cassette torrents may be reported and will be deleted if no note exists of prior staff approval. Anyone found falsifying staff notes will have their uploading privileges removed. +
    • +
    • ↑_ 2.1.15. The only lossy multichannel audio formats allowed are AC3 and DTS. If the source is DTS or AC3, do not transcode to other formats. Exceptions: Transcoding is allowed if the source is lossless (LPCM or MLP). Those should be compressed with multichannel FLAC. Note: DTS-CD rips cannot be re-compressed to a lossless codec and they must be kept as WAV files with the .dts extension. + +
    • +
    • ↑_ 2.1.16. SACD hybrid rip sources must be properly labeled. SACD hybrid discs ripped from the CD layer should be labeled as CD and not SACD. If you used your CD/DVD drive and a CD ripper (such as EAC) to extract the audio, then label it as "CD" source (i.e. it's not true 24-bit). If the rip came from the genuine digital SACD layer through a SACD player mod or line out, it should be 24-bit quality SACD. You may include "SACD Hybrid" in the Edition Information box on the upload page. +
    • + +
    • ↑_ 2.1.17. WEB media is for digital downloads only. Digital downloads released only on the internet from internet sources cannot be given the CD media label on the upload page. This includes downloads from the iTunes Store, LiveDownloads, Beatport, Amazon.com, Rhapsody, and other webstores. Scene releases with no information of sources must also be labeled as WEB. Freely available music with no source information must also be labeled WEB. If possible, indicate the source of your files (e.g. webstore) in the torrent description. You are responsible that the downloaded files conform to What.CD's rules for music quality. Note: Do not confuse WEB for web rips. WEB media torrents are not always web rips (transcodes). Please check the spectrals before assuming they are web rips. +
    • +
    • ↑_ 2.1.18. User-made compilations are not allowed. Compilations must be reasonably official. For example, "34 of my favourite Grateful Dead songs" is not a reasonably official collection. Compiling a release from a list, such as a Top 100 Billboard Chart, is not allowed. User-made and unofficial multichannel mixes are also not allowed. Exceptions: Bootlegs are allowed if they meet quality standards for music and are proven to be retail releases in digital or physical form. Bootlegs/mixtapes assembled and available from internet-only sources (e.g. music blogs, message boards, etc.) are not considered official enough for this site. +
    • + +
    • ↑_ 2.1.19. No comedy, audio books, or spoken word releases may be uploaded in the music category. Spoken word releases are governed by a different set of standards than music. Thus they do not belong in the music category. +
    • +
    • ↑_ 2.1.20. Sound sample packs must be uploaded to the Applications category. These releases are allowed only under the apps category; they are forbidden in music and other categories. Sound sample packs may use formats other than those allowed for music, and must be official collections. See 3.1.8. for more information. +
    • + +
    • ↑_ 2.1.21. All music torrents must represent a complete album (a complete collection release). Albums must not be missing tracks, or discs in the case of a multi-disc release. All music torrents must be one release. If an album is released as a multiple set of CDs, then it must be uploaded as a single torrent. Uploading each disc separately is not allowed. Digital downloads of albums must consist of entire albums. If tracks are available separately, but not released as singles, you may not upload them individually. Exceptions: Bonus discs may be uploaded separately in accordance with this rule. Please note that individual bonus tracks are not allowed to be uploaded without the rest of the album. Bonus tracks are not bonus discs. Enhanced audio CDs with data or video tracks must be uploaded without the non-audio tracks. If you want to share the videos or data, you may host the files off-site with a file sharing service and include the link in your torrent description. +
    • +
    • ↑_ 2.1.22. Multi-album torrents are not allowed on the site under any circumstances. That means no discographies, Pitchfork compilations, etc. Discographies make it a hassle for users to download individual albums. They result in a lot of duplicate albums being uploaded and are generally very poor quality. If releases (e.g. CD singles) were never released bundled together, do not upload them together. Live SBD material should be one torrent per night, per show, or per venue. Including more than one show in a torrent results in a multi-album torrent. Exceptions: Only official boxsets and official compilation collections can contain multiple albums. +
    • +
    • ↑_ 2.1.23. Edition Information must be provided for digitally-sourced torrents. Digitally-sourced (including CD-sourced) rips of material first released before the availability of their source medium must have accurate edition information. For example, if a CD rip of an album whose original release date was 1957, predating the creation and distribution of CDs, then the uploader must make note of the correct year the CD was pressed, and preferably catalog identification as well. Rips for which Edition Information cannot be provided must be marked as an 'Unknown Release'. Under no circumstances must you guess or feign Edition Information. +
    • +
    • ↑_ 2.1.24. Downsampling of analog rips is allowed. Analog rips that have been downsampled may be uploaded (e.g. a 24/96 vinyl rip downsampled to 16/44). Any downsampled torrents must include the specific programs and methods used to downsample in addition to the lineage for the original rip or it will be deleted. NOTE: downsampling of CDs is expressly forbidden. +
    • +
    • ↑_ 2.1.25. Pre-emphasis is allowed in lossless torrents only. Lossless FLAC torrents with pre-emphasis are allowed on the site. They are allowed to co-exist with lossless de-emphasised torrents. On the other hand, lossy formats may not have pre-emphasis and will be deleted if uploaded. +
    • +
    + +
    + +
    2.2. Duplicates & Trumping
    +
    +
      +
    • 2.2.0. Overview + +

      + Audio Dupe and Trump Chart
      This chart is an overview of how the dupe and trump rules work. +

      +
    • +
    • ↑_ 2.2.1. Upload an allowed format if it doesn't exist on the site. If there is no existing torrent of the album in the format you've chosen, you can upload it in any bitrate that at least averages 192kbps. +
    • + +
    • ↑_ 2.2.2. Same bitrates and formats of the same releases are duplicates. If a torrent is already up in the format and bitrate you want to upload it in, you are not allowed to upload it–it's a duplicate (dupe). So if there's a 192kbps CBR MP3 version on the site, you are not allowed to upload another 192kbps CBR MP3. You cannot trump an existing torrent with a version that includes album art. Exceptions: Different editions and source media do not count as dupes. Refer to rule 2.2.6. for more information. +
    • +
    • ↑_ 2.2.3. Report all trumped and duplicated torrents. If you trump a torrent or notice a duplicate torrent, please use the report link (RP) to notify staff for removal of the old or duplicate torrent. This especially applies to lossless rips. If you are uploading a superior rip to the current one in the same format on the site, report the older torrent and include a link to your torrent in the report. Your torrent will be deleted as a dupe if the older torrent is not reported. Note: Trump = You can trump a torrent that exists on the site by uploading a torrent in a preferred bitrate or quality as specified in the rules below. A torrent that is trumped by another torrent is considered a duplicate ("dupe") of the superior torrent, since the two torrents are not allowed to coexist on the site. + +
    • +
    • ↑_ 2.2.4. Dupe rules also apply against previous uploads. All of the following dupe rules concerning music formats in this section may apply to torrents uploaded before. For example, if you upload an album in 192kbps MP3, someone can upload the same album in 320kbps at a later date and trump your 192kbps MP3. +
    • +
    • ↑_ 2.2.5. Scene and non-scene releases of the same release, bitrate, and format are dupes. The "scene" label does not make torrents unique from each other. If a scene -V2 (VBR) of an album from CD is already uploaded, you may not upload another -V2 (VBR) of the same album from CD. +
    • + +
    • ↑_ 2.2.6. Different editions and source media count as separate releases. A rip from a different medium (e.g. vinyl) or release (e.g. a remaster) of an already existing torrent counts as a different release. The dupe rules do not apply between the two different edition torrents, nor two differently sourced torrents. So if a FLAC ripped from a CD is already up, you are still allowed to upload a FLAC ripped from vinyl. And if a 320kbps CBR MP3 release of an original mastering of an album was uploaded, you are still allowed to upload a 320kbps CBR MP3 remaster. Exceptions: Only one edition of each unofficial live recording is allowed. Such bootlegs can be unofficially remastered several times, and such constant remastering is of little consequence on a site where bootlegs are not the primary focus. Only one unofficial soundboard recording of each show is allowed, and it should be uploaded on the torrent page with no edition information selected. +
    • +
    • ↑_ 2.2.7. Complete or untouched releases replace incomplete or watermarked versions. Watermarked promos containing voice-overs and similar can be trumped by a non-watermarked release. Releases missing hidden or pre-gap tracks can be replaced by proper rips that include the range. These hidden or pre-gap tracks should be in their own file, not appended to the beginning of track one, and releases where the hidden track or pre-gap is appended can be trumped by one where the track is a separate file. +
    • +
    • ↑_ 2.2.8. Bonus disc-only uploads can co-exist with the complete set in accordance with the trumping rules. A bonus disc-only release can be trumped by an upload containing the "full" original album + bonus discs, in the same format, in accordance with the usual trump rules. +
    • + +
    • ↑_ 2.2.9. Higher bitrate CBR (Constant Bitrate) and ABR (Average Bitrate) torrents replace lower ones. Once a CBR (Constant Bitrate) rip has been uploaded, no CBR rips of that bitrate or lower can be uploaded. In the same manner, once an ABR (Average Bitrate) rip has been uploaded, no ABR rips of that bitrate or lower can be uploaded. For example, if a 320kbps CBR rip is already on the site, you are not allowed to upload a 256kbps CBR. ABR and CBR may be interchangeably trumped. A CBR can trump a lower bitrate ABR and an ABR may trump a lower bitrate CBR. You may not upload a 192kbps CBR if a 256kbps ABR of the same release is already up. +
    • +
    • ↑_ 2.2.10. Lossy format torrents with .log files do not replace equivalent existing torrents. If you want to upload a lossy format (e.g. MP3, Ogg Vorbis, AAC, etc.) with a log that already exists in the same medium and edition, you may not replace the current lossy torrent. For example, a -V2 (VBR) MP3 torrent with a log cannot replace a -V2 (VBR) without a log. Same applies for lossy audio torrents with .m3u, .cue, and other additions such as artwork. Exceptions: If an existing torrent contains encode/rip errors, you may upload another copy without errors. The bad torrent needs to be reported or yours will be deleted as a dupe. Also, see rules 2.3.8 through 2.3.16 for replacing badly named and tagged torrents. +
    • + +
    • ↑_ 2.2.11. Vinyl Specific Dupe Rules +
        +
      • ↑_ 2.2.11.1. Only one lossy vinyl rip in a specific bitrate is allowed per release. Once someone has uploaded a lossy-format vinyl rip (in MP3, Ogg Vorbis or AAC), you may not upload another copy in the same bitrate. It does not matter whether if the lossy files are of a different sample rate found on the site. For example, if a 48 kHz -V2 (VBR) copy is already up, you may not upload the same album in -V2 (VBR) at 44.1 kHz. +
      • +
      • ↑_ 2.2.11.2. Only one lossless and one 24bit lossless vinyl rip is allowed per edition. A poor sounding lossless rip may be trumped by a better sounding lossless rip, regardless of lineage information. The same quality trump can occur for 24bit lossless rips. To trump a rip for a better sounding version, you need to report it with clear informations about how your rip sounds better than the other one. Rips of extremely poor quality may be deleted outright if reported. All quality trumps/deletions of this nature are at the discretion of the moderator involved. +
      • +
      • ↑_ 2.2.11.3. All vinyl torrents must be ripped at the correct speed. You must rip all vinyl at the speed they were intended to be played at. For example, you may not rip a 45rpm vinyl at 33rpm and upload it to the site. +
      • +
      +
    • ↑_ 2.2.12. MP3 Specific Dupe Rules +
        +
      • ↑_ 2.2.12.1. -V0 (VBR), -V2 (VBR), and 320 CBR MP3 are allowed at any time. You may upload a -V0 (VBR), -V2 (VBR) or 320 CBR MP3 as long as another rip with the same bitrate and format doesn't already exist. So if a -V0 (VBR) is on the site, you may still upload a -V2 (VBR) or 320 CBR MP3 of the same release. +
      • + +
      • ↑_ 2.2.12.2. -V2 (VBR) and APS (VBR) replace CBR rips under 256kbps, 192 (ABR), and rips averaging 192 (VBR) to 210 (VBR). Once a rip with either -V2 (VBR) or APS (VBR) LAME encoding preset has been uploaded, you are not allowed to upload any CBR torrents under 256kbps bitrate. Furthermore, a -V2 (VBR) or APS (VBR) rip will trump all indiscriminate VBR rips of similar bitrate. A -V2 (VBR) rip will replace a 192 (VBR) rip or 210 (VBR) rip for example. Also, a -V2 (VBR) will replace a 192 (ABR) torrent. +
      • +
      • ↑_ 2.2.12.3. -V0 (VBR) and APX (VBR) replace CBR rips under 320kbps, V1 (VBR), all (ABR) rips, and all other non-LAME preset (VBR) rips. Once a rip with either -V0 (VBR) or APX (VBR) LAME encoding preset has been uploaded, you are not allowed to upload any CBR torrents under 320kbps bitrate. Furthermore, a -V0 (VBR) or APX (VBR) rip will trump all indiscriminate VBR rips (of 192kbps average bitrate or higher). A -V0 (VBR) rip will replace a 256 (VBR) rip for example. You may not upload a -V1 (VBR) LAME encoding preset if either -V0 (VBR) or APX (VBR) are already present. +
      • +
      • ↑_ 2.2.12.4. Non-LAME preset (VBR) rips do not replace each other. Similar bitrate (VBR) encodes are considered dupes. Thus, a 192 (VBR) is allowed to co-exist with a significantly higher (VBR) encode. You may not upload a 224 (VBR) if a 256 (VBR) is already present, nor vice versa. +
      • + +
      • ↑_ 2.2.12.5. -V2 (VBR) and -V0 (VBR) LAME encodes trump APS (VBR) and APX (VBR) respectively. -V2 (VBR) trumps an APS (VBR) encode of the same release. Once a -V2 (VBR) is uploaded, you may not upload an APS (VBR) encode. -V0 (VBR) trumps an APX (VBR) encode of the same release. Once a -V0 (VBR) is uploaded, you may not upload an APX (VBR) encode. +
      • +
      +
    • +
    • ↑_ 2.2.13. Ogg Vorbis Specific Dupe Rules + +
        +
      • ↑_ 2.2.13.1. Only -q8.x (VBR) and equivalent presets (-q0.8) are allowed. Only -q8.x (~256 (VBR)) is allowed on the site for Ogg Vorbis. Torrents encoded with presets other than -q8.x will be deleted. You may use fraction presets where x is any number from 0 - 9. Fraction presets do not make your upload unique from all similar presets. You may not upload a -q8.1 (VBR) if a -q8.7 (VBR) is already present. +
      • +
      +
    • +
    • ↑_ 2.2.14. AAC Specific Dupe Rules + +
        +
      • ↑_ 2.2.14.1. No constant bitrate encodes higher than 320 CBR are allowed on the site. You may upload AAC files from 192kbps to 320kbps if no torrent exists in that format for a release. Any CBR bitrates under 192kbps and bitrates higher than 320kbps will be deleted. CBR trumping rules apply to AAC as well. See 2.2.9 for more information. +
      • +
      • ↑_ 2.2.14.2. Encoding profiles/object types at the same bitrate are not unique uploads. A 256 (VBR) in LC profile is a dupe if an 256 (VBR) HE object type encode already exists on the site. Similarly, different extensions (.m4a and .mp4) count as dupes if available in the same bitrate. +
      • + +
      • ↑_ 2.2.14.3. VBR AAC encodes can be trumped by 320 CBR encodes. Any (VBR) encode regardless of encoder used may be deleted in favor of 320 CBR encodes. This includes 320 (VBR) encodes or encodes made with Nero preset of approximately -q0.80. +
      • +
      +
    • +
    • ↑_ 2.2.15. Lossless Specific Dupe Rules + +
        +
      • ↑_ 2.2.15.1. All FLAC CD rips must come from official CD sources. Rips must be taken from commercially pressed or official-pressed CD sources. They may not come from CD-R copies of the same pressed CDs. Undetected errors may be introduced from the original CD rip and subsequent burning process to CD-R. Even though the CD-R is ripped with proper settings in XLD or EAC, it may still be a sub-par rip with a good log. Exceptions: If the release is only distributed on CD-R, then that is acceptable. Promotions and small distributions of albums tend to be in CD-R format. +
      • + +
      • ↑_ 2.2.15.2. A FLAC torrent without a rip log can be trumped by a FLAC torrent of the same release containing a rip log. The FLAC torrent without a log will be trumped in favor of one containing a log. Please make sure your rip log has the extension .log in order to be displayed properly on the torrents page. Exceptions: If the FLAC torrent with a log contains excessive rip errors (e.g. suspicious positions, skips, or pops), it cannot replace the existing torrent. Audiochecker, auCDtect, and other MPEG analyzer logs do not count as rip logs, even if renamed with the .log extension. Soundboards and other exclusive lossless digitally-distributed files cannot be unofficially burned to CD-R and re-ripped in order to trump existing digital copies of the same quality and source. +
      • +
      • ↑_ 2.2.15.3. A FLAC upload with an EAC or XLD rip log that scores 100 on the logchecker replaces one with a lesser score. Proper EAC or XLD rips can replace rips made by other rippers or with sub-par settings. No log scoring less than 100 can trump an already existing one under 100. For example, a FLAC+log rip that scores a 50 in the logchecker can not be trumped by a FLAC+log that scores an 80. What.CD recommends caaok's guide for EAC, and this guide for XLD. What.CD strongly encourages enabling AccurateRip if available for your CD extraction app of choice. Note: If a log scores 95 due to not defeating audio cache, and the torrent description contains accepted proof of the drive for ripping caches less than 64 kB of audio data, then that torrent can not be trumped by a torrent with a 100 score. The 95 torrent may be upgraded to 100 once a staff member has been alerted to the case, and has manually corrected the score. See 2.2.15.7. + +
      • +
      • ↑_ 2.2.15.4. XLD and EAC log in languages other than English require manual logchecker score adjustment. The current logchecker cannot parse non-English logs made by EAC and XLD. However, a special exception is made for foreign-language logs since the rip quality is equivalent to English logs. Please report your torrent with the RP link so staff can approve your torrent manually. +
      • + +
      • ↑_ 2.2.15.5. Range rips of hidden tracks or range rips under strict conditions require manual score adjustment. The new logchecker cannot accurately score range-ripped hidden tracks appended to proper rip logs. If you have created a 100 rip with a hidden track, but the logchecker decreased your score for the hidden track, report the torrent. That way your score can be adjusted to reflect the proper settings. What.CD does not encourage ripping entire CDs as range rips. Instead, please rip CDs to separate tracks according to the EAC Guide. For those rare cases where you have created a CD image rip with matching CRCs for test and copy, and the tracks have a AccurateRip verification of 2 or more, then you may submit your torrent for manual adjustment. Note: The CD Image rip must be split with CUE Tools, XLD, or EAC. No other splitter is acceptable for a score adjustment. You will not receive score adjustment for copy-only range rips approved with AccurateRip nor range rips done with test and copy only. + +
      • +
      • ↑_ 2.2.15.6. A 100% log rip lacking a cue sheet can be replaced by another 100% log rip with a noncompliant cue sheet ONLY when the included cue sheet is materially different than 'a cue generated from the ripping log'. Examples of a material difference include additional or correct indices, and pre-emphasis flags. If you upload a torrent with a cue sheet that provides nothing additional beyond what is contained in the ripping log of the preexistent torrent, it will be deleted as a dupe. Exception: An EACv0.95 rip with a 100% log and no cue file uploaded before September 14, 2010 may be trumped by a torrent that scores 100% under the current logchecker. +
      • +
      • ↑_ 2.2.15.7. Drives that cache less than 64 kB of audio data may leave the audio cache enabled. Proof is required. They can be trumped by a 100 rip if no proof is included. Under certain conditions, rips made without the audio cache disabled may trump other rips if all other settings are correct. A pasted log (hosted at Pastebin or similar site is OK) or screenshot of proof from Feurio! and a screenshot from CacheX should be posted in the torrent description field. See the Wiki page for examples of allowed proof. You will need to present proof from both CacheX and Feurio!. EAC's own cache detection may give erroneous results sometimes, so a screenshot of EAC's drive features test cannot serve as proof. Also, XLD logs before CDParanoia III 10.2 engine require AccurateRip verification because the cache is not properly defeated on earlier CDParanoia versions. Please report your torrent with the RP link so staff can approve your torrent manually to 100 score. +
      • +
      • ↑_ 2.2.15.8. FLAC rips that contain ID3 tags or other non-compliant tags for FLAC may be trumped by same score rips that have faulty tags removed and replaced with the standard for each format. Enabling ID3 tags in EAC when ripping to FLAC may prevent some players from playing the files due to the inclusion of ID3 headers. If you wish to trump a FLAC rip that was ripped with ID3 tags enabled, upload the corrected torrent with the proper Vorbis comments, and report the old torrent. Add information about your clean-up in the Release description, or your torrent may be deleted for a dupe. Do not edit the log and change the ID3 tag setting to "No." Note: A simple way of getting rid of the ID3 header is to decompress the files to WAV. Then compress the files to FLAC, and again add the proper Vorbis comments. + +
      • +
      • ↑_ 2.2.15.9. No log editing is permitted. Forging log data is a serious misrepresentation of quality, and will result in a warning and permanent loss of upload privileges if found. Do not consolidate logs under any circumstances. If you must re-rip a disc and happen to have the new log appended to the original, leave them as-is. Do not remove any part of either log, and never copy/paste parts of a new log over an old log. If you find that an appended log has not been scored properly, please PM a moderator to get the score manually adjusted. +
      • + +
      +
    • +
    • ↑_ 2.2.16. Unknown Release torrents may be trumped by seemingly identical torrents whose Edition Information can be verified. Torrents marked as 'Unknown Release' are eligible to be trumped by rips sourced from the same medium, of the same track listing and running order, whose source Edition Information is provided and can be verified. +
    • +
    +
    + +
    2.3. Formatting
    +
    +
      +
    • ↑_ 2.3.1. Music releases must be in a directory containing the music. No music contained in an archive (e.g. .rar, .zip, .tar, .iso). Scene archives of music must be unpacked and not labeled as "scene." Exceptions: There is no need for a directory for a torrent that consists of a single file (and is not an archive!). +
    • + +
    • ↑_ 2.3.2. Name your directories with meaningful titles, such as "Artist - Album (Year) - Format." We advise that directory names in your uploads should at least be "Artist - Album (Year) - Format". The minimum acceptable is "Album", although it is preferable to include more information. If the directory name does not include this minimum then another user can rename the directory, re-upload and report yours for deletion. Avoid creating unnecessary nested folders (such as an extra folder for the actual album) inside your properly named directory. Nested folders make it less likely that downloaders leave the torrent unchanged in order to stay seeding. +
    • +
    • ↑_ 2.3.3. Label your torrents according to standards. Follow the torrent naming guide for help on how to name your uploaded torrents properly. Note that soundboards, EPs, LPs. singles, special characters, and releases with various artists have special naming standards here. Use the Edition Information box on the upload page to denote different editions or versions of an album (e.g. censored version versus an uncensored version). Do not add genre tags like [Australia] or [K-Pop] to your album title. Those belong as Gazelle tags. If you need help merging or editing your upload, request it at this thread. For the album category/release type, follow the guidelines here. +
    • + +
    • ↑_ 2.3.4. Torrents should never have [REQ] or [REQUEST] in the title or artist name. If you fill a request using the proper Requests system, then everyone who voted for it will be automatically notified. +
    • +
    • ↑_ 2.3.5. Torrent album titles must accurately reflect the actual album titles. Use proper capitalization when naming your albums. Typing the album titles in all lowercase letters or all capital letters is unacceptable. For detailed information on naming practices see this. Exceptions: If the album has special capitalization, then you may follow that convention. +
    • + +
    • ↑_ 2.3.6. The Artist field in the torrent name should contain only the artist name. Any descriptions like [Advance] or [CDM] (if you must use them) should be entered in the Edition Information box on the upload page, not the title. Do not add additional information about the artist in the artist field unless the album credits the artist in that manner. For example, "Artist X (of Band Y)" or "Band X (feat. Artist Y)." It is recommended that you search existing torrents for the artist name so that you can be sure that you name the artist the exact same way. A torrent with a proper artist name will be grouped with the existing torrents on the artist page, and thus easy to find. Labeling the artist incorrectly prevents your torrent from being grouped with the other torrents of the same artist. +
    • +
    • ↑_ 2.3.7. The year of the original recording should be used for the upload page "Year" box. Use the recording year for "Year of the original release" (if you can establish it), and use the option to add the release year for the album or edition you are uploading in the Edition information on the uploads page. For example, all editions of The Beatles (White Album) would have 1968 in the main Year box. However, each of the various mono pressings, remasters, re-releases, expanded editions, reconstructions, etc. would have its respective release year in the Edition Information box. +
    • +
    • ↑_ 2.3.8. All lossless analog rips should include clear information about source lineage. All lossless SACD digital layer analog rips and vinyl rips must include clear information about recording equipment used. If you used a USB turntable for vinyl, clearly indicate that you have. Also include all intermediate steps up to lossless encoding, such as program used for mastering, sound card used, etc. Lossless analog rips missing rip information can be trumped by better documented lossless analog rips of comparable or better quality. In order to trump a lossless analog rip without a lineage, this lineage must be included as a .txt or .log file within the torrent. +
    • +
    • ↑_ 2.3.9. All lossless soundboard recordings must include clear information about source lineage. This information should be displayed in the torrent description. Optionally, the uploader may include the information in a .txt or .log file within the torrent. Lossless soundboard recordings missing lineage information will be deleted if reported. +
    • +
    • ↑_ 2.3.10. File names must accurately reflect the song titles. You may not have file names like 01track.mp3, 02track.mp3, etc. File names with incorrect song titles can be trumped by properly labeled torrents. Note that these must be substantial improvements such as the removal of garbage characters. Small changes such as diacritical marks are insufficient grounds for trumping. English translations of song titles in file names are encouraged, but not necessary for foreign language song titles. Exceptions: Rare albums featuring no track listing or untitled tracks may have file names like 01track.mp3, 02track.mp3, and so forth. Please note this tracklist in the Album description. If foreign language characters create playback problems for some systems or cannot be coherently translated, file names such as "01track" is acceptable for those few cases. +
    • +
    • ↑_ 2.3.11. Including track numbers of each song in the file names (e.g. "01 - TrackName.mp3") is highly recommended. If a torrent without track numbers in the file names is uploaded, then a torrent with the track numbers can take its place. Exception: Track numbers are not required for single-track torrents. +
    • +
    • ↑_ 2.3.12. Multiple-disc torrents cannot have tracks with the same numbers in one directory. Tracks cannot contain duplicate track numbers in the same directory. You may either place the tracks for each disc in a separate directory or number the tracks successively. You may place all the tracks for Disc One in one directory and all the tracks for Disc Two in another directory. If you prefer to use one directory for all the audio files, you must use successive numbering. Successive numbering may consist of the following (as illustrated with examples). Disc One has 15 tracks and Disc Two has 20. You may either number tracks in Disc One as #01-#15, and those of Disc Two as #16-#35 in the same directory. Or you may add a Disc number before the track numbers, such that the numbers are #1 06 for Disc One Track 06, and #2 03 for Disc 2 Track 03, and so forth. That way the track numbers will not be duplicated across multiple discs. +
    • +
    • ↑_ 2.3.13. Properly tag your music files. Certain meta tags (e.g. ID3, Vorbis) are required on all music uploads. Make sure to use the proper format tags for your files (e.g. no ID3 tags for FLAC – see rule 2.2.15.8). ID3v2 tags for files are highly recommended over ID3v1. Torrents uploaded with both good ID3v1 tags and blank ID3v2 tags are trumpable by torrents with either just good ID3v1 tags or good ID3v2 tags. If you upload an album missing one or more of these tags, then another user may add the tags, re-upload, and report yours for deletion. The required tags are: +
        + +
      • Artist
      • +
      • Album
      • +
      • Title
      • +
      • Track Number.
      • +
      +

      Note: The "Year" tag is optional, but strongly encouraged. However, if missing or incorrect, is not grounds for trumping a torrent.

      +

      Note: Classical music has a different tagging standard. In particular, classical music uploads must have both the composer and artist tagged properly. See this article for more information. +

    • +
    • ↑_ 2.3.14. The torrent artist for classical works should use the full composer name. Please consult this article for a full explanation of the classical music system. +
    • +
    • ↑_ 2.3.15. Newly re-tagged torrents trumping badly tagged torrents must reflect a substantial improvement over the previous tags. Small changes that include replacing ASCII characters with proper foreign language characters with diacritical marks, fixing slight misspellings, or missing an alternate spelling of an artist (e.g. excluding "The" before a band name) are insufficient grounds for replacing other torrents. You may trump a release if the tags do not follow the data from a reputable music cataloging service such as Musicbrainz or Discogs. In case of conflict between reputable listings, either tagged version is equally preferred to the site and cannot trump the other. For example, an album is tagged differently in Musicbrainz and in Discogs. Either style of tagging is permitted; neither is "better" than the other. In that case, any newly tagged torrents replacing an already properly tagged torrent, which follows good tagging convention, will result in a dupe. Note: For classical music, please follow our tagging guidelines. + +
    • +
    • ↑_ 2.3.16. Avoid embedding large images if including cover art in meta tags. Do not embed large images (in excess of ~256 KB) in file meta tags. It adds unnecessary bloat to the files. Include the artwork in a separate directory if too big or hi-res. If someone reports your torrent for large embedded artwork, it will be deleted. +
    • +
    +
    + +

    3. Applications

    + + +
    3.1. General
    +
    +
      +
    • ↑_ 3.1.1. App releases can be either a torrent of a directory or an archive. Exceptions: Only scene released applications may be archived and must not be password protected. If archives were originally password protected and had the protection removed, they cannot be represented as official scene releases. The file hashes between protected and unprotected archives are different, so it counts as a modification. +
    • + +
    • ↑_ 3.1.2. All applications must come with a crack, keygen, or other method of ensuring that downloaders can install them easily. App torrents with keygens, cracks, or patches that do not work and torrents missing clear installation instructions are deleted if reported. No exceptions. +
    • +
    • ↑_ 3.1.3. App releases must not be freely available tools. Application releases cannot be freely downloaded anywhere from any official source. Nor may you upload open source apps where the source code is available for free. Closed or shareware installers like Crossover Office are allowed. Note: If all official sources stop hosting and remove a freely available app and its source code from their site(s) due to varying reasons (legal, dead development, etc.), the app ceases to be freely available. You may upload it in that case. + +
    • +
    • ↑_ 3.1.4. Release descriptions for apps must contain good information about the application. You should either have a small description of the program (either taken from its website or from a NFO) or a link to information–ideally both. +
    • +
    • ↑_ 3.1.5. The torrent title must have a descriptive name. The torrent title should at least include the app name and release version. Optionally, you may include additional labels for OS and kind of circumvention (i.e. crack, patch, keygen, or serial). For example, AcrylicApps Wallet v3.0.1.493 MacOSX Cracked. +
    • + +
    • ↑_ 3.1.6. Use relevant tags for your torrent. Add all applicable default Gazelle tags to help downloaders find your torrent. The default tags are apps.mac for Mac apps, apps.windows for Windows apps, and apps.sound for audio apps. You may add additional tags if the default ones do not apply (such as apps.linux). +
    • +
    • ↑_ 3.1.7. Application "packs" are not allowed. That means no 0-day packs or "video utilities" compilations. Exceptions: The applications are from the same company and an official release. For example, Adobe CS and Macromedia Studio. +
    • + +
    • ↑_ 3.1.8. Sound sample packs, template collections, and font collections are allowed if they are official releases, not freely available, and unarchived. Sound sample packs, template collections, and font collections must be official compilations. The files contained inside the torrent must not be archived. That means if sound sample packs are in WAV format, they must be uploaded as WAV. If the font collection, template collection, or sound sample pack was originally released as an archive, you must unpack the files before uploading them in a torrent. None of the content in these packs and collections may be freely available. +
    • +
    • ↑_ 3.1.9. Application components such as plug-ins, add-ons, expansions, filters, and so forth may be uploaded in a collection if they correspond to a particular application. You may upload plug-ins, expansions, add-ons, filters, and other application components as collections provided they are compatible to a particular application and version. For example, you may not upload a megapack of all filters for Adobe Photoshop CS2, CS3, and CS4. But you may upload a pack of Adobe Photoshop CS4 filters. +
    • + +
    • ↑_ 3.1.10. Collections of cracks, keygens or serials are not allowed. The crack, keygen or serial for an application must be in a torrent with its corresponding application. It cannot be uploaded separately from the application. +
    • +
    • ↑_ 3.1.11. Torrents containing hacking or cracking tools are not allowed. +
    • +
    • ↑_ 3.1.12. Never post serial numbers in torrent descriptions. Serial numbers should be in a text file (or similar) contained within the torrent. No exceptions. +
    • +
    • ↑_ 3.1.13. All applications must be complete. If an application consists of multiple CDs or DVDs, these should all be uploaded as one torrent, and not as separate torrents. This also applies to scene uploads where multiple CDs or DVDs were released separately. +
    • +
    +
    + +
    3.2. Duplicates & Trumping
    +
    +
      +
    • ↑_ 3.2.1. Applications of the same version numbers are dupes. An application may have older versions than those already uploaded. Those are not dupes. Only identical versions are duplicates. +
    • + +
    • ↑_ 3.2.2. A scene archived torrent may coexist with an unarchived torrent of the same app version. If both an scene archive and an unarchived copy are uploaded of the same app and version, both may stay on the site. Any subsequent uploads of the same in either format or install method are dupes. +
    • +
    • ↑_ 3.2.3. Different language editions of the same app and version are unique. Multi-language versions and single language versions of different languages are not considered dupes. +
    • +
    • ↑_ 3.2.4. Apps can be trumped by other apps with better install methods. Apps with serial keys may be trumped by crack/patch versions or torrents with keygens. Once an app with either a crack/patch or keygen is uploaded to the site, no other identical app with a different method of install is allowed. Report the old torrent if trumping it with a torrent of the same app and improved method of installation. +
    • + +
    +
    + +

    4. Comic Books

    + +
    4.1. General
    +
    +
      + +
    • ↑_ 4.1.1. Comic books must be in the specified formats. These formats are the following according to descending preference: +
        +
      • A rar archive (Preferably with the .cbr extension)
      • +
      • A zip archive (Preferably with the .cbz extension)
      • +
      • A PDF file
      • + +
      • A directory containing only the images themselves
      • +
      +
    • +
    • ↑_ 4.1.2. Pages must be scanned cleanly and be of good quality. Scans of poor quality will be deleted, especially if the quality is so poor as to render difficulty in reading. Poorer quality scans may be acceptable for very old or rare comics with staff discretion. +
    • +
    • ↑_ 4.1.3. Comic books must not be freely available. Comics must be official publications, and these cannot be taken from official sources. You may upload comics from other torrent and unofficial distribution sites, but it is your responsibility that they conform to our quality and formatting rules for comic books. Note: If all official sources stop hosting and remove an official freely available release from their site(s), the release ceases to be freely available. You may upload it in that case. + +
    • +
    • ↑_ 4.1.4. 0-Day comic uploads are allowed and encouraged. +
    • +
    +
    + +
    4.2. Multi-comic
    + +
    +
      +
    • ↑_ 4.2.1 Multi-comic and series packs must follow formatting requirements. Multi-comic and series packs are both accepted and encouraged but care must be taken to make a valid compilation. The rules below outline the requirements for multi-comic torrents. +
    • +
    • ↑_ 4.2.2. 0-Day comic packs are allowed. Make sure such uploads are synchronized with previous packs. 0-Day comic uploads must not be missing any of their corresponding DCP or Minutemen scans for that sync time. +
    • + +
    • ↑_ 4.2.3. Collections may not span more than one comic title. You may not collect multiple different comic titles. e.g. "The Amazing Spider-Man #1 and The Incredible Hulk #1" Exceptions: Titles may contain more than one comic title if either: it's a recognized comic crossover/event or it's a DCP weekly release. +
    • +
    • ↑_ 4.2.4. Any "multi-part" comic enveloping the whole event is allowed as a single torrent. Whole events may be uploaded together. For example, the comics "Buffy the Vampire Slayer Season Eight - 2007 - part 1.cbr" and "Buffy the Vampire Slayer Season Eight - 2007 - The Long Way Home Part 2.cbr" can be uploaded as a single torrent providing there are only 2 parts to "The Long Way Home." +
    • + +
    • ↑_ 4.2.5. Torrents containing complete volumes of comics may be uploaded. For example, "The Amazing Spider-Man Vol. 1 #1-#441" can be uploaded. +
    • +
    • ↑_ 4.2.6. Torrents spanning multiple volumes are too large and must be uploaded as separate volumes. +
    • +
    • ↑_ 4.2.7. Torrents containing #Number-#CurrentDay are allowed only if the comics appear in no other pack. Take for instance, if #1-#35 are already on site and the current issue is #50, #1-#50 is NOT allowed to be uploaded, but #36-#50 is allowed. +
    • + +
    +
    + +
    4.3. Duplicates & Trumping
    +
    +
      +
    • ↑_ 4.3.1. A dupe of a single comic is defined as two scans of the same book by the same scanner, where the same pages have been scanned. Exceptions: The following examples are NOT dupes: +
        + +
      • Two copies of the same book by the same scanner, but one is a c2c copy and the other is a "no ads" copy
      • +
      • Two scans of the same book by different scanners
      • +
      • Two scans of the same book by the same scanner, when the copy you're uploading contains fixes
      • +
      +
    • +
    • ↑_ 4.3.2. Releases in .cbz and .cbr are always allowed, with preference given to the earliest upload. In the event of a dupe occurring between a .cbr and a .cbz, the earliest upload remains. In the event of any other dupe, the order listed in 4.1.1 determines which torrent is kept regardless of uploaded time. e.g. A PDF is uploaded followed by a .cbr, the .cbr remains on site and the PDF is deleted as a dupe. +
    • + +
    • ↑_ 4.3.3. Multi-comic collections and packs must follow either of these collection types in order of preference. For example, there is the torrent #1-50 on site, the only pack containing any of the comics before #50 that are allowed to be uploaded are a #1-100 pack or a complete volume pack. +
        +
      • #1-#10, #11-#20, #21- #40, etc. are allowed only if comics appear in no other pack. They must contain at least 10 new comics. +
      • +
      • #1-#100, #101-#200, etc. are allowed only if they are not a complete volume pack. +
      • + +
      • #1-#EndOfVolume is allowed at any time. +
      • +
      +
    • +
    +
    + +
    4.4. Formatting
    +
    + +
      +
    • ↑_ 4.4.1. All comic page scans must be zero-padded numbered and may be archived properly in .pdf, .rar (.cbr) or .zip (.cbz). The contents of the archive or directory must be image files (either JPEG or PNG) named sequentially for display in the correct order by comic reading software such as CDisplay and FFView. The page numbers and books must be zero-padded for this same reason. For example, Good numbering: file01.jpg, file02.jpg .. file30.jpg and Bad numbering: file1.jpg, file2.jpg, file3.jpg...file30.jpg. + +
    • +
    • ↑_ 4.4.2. Comic book archive file names must be informative. The archive names should include at least the Book's name (i.e. Uncanny X-Men), the volume (if there's more than one volume of that book) and the issue number. It is recommended to also include the cover year and the scanner information (to differentiate between different scans of the same book), as well as the issue's title (i.e. Days of Future Past). For example: Buffy the Vampire Slayer Season Eight - #01 - 2007 - The Long Way Home Part 1.cbr and Amazing Spiderman - Volume 1 - #10 - 1964.cbz +
    • +
    • ↑_ 4.4.3. The directory name should uniquely identify its contents. You should include the title, as well as the issue numbers included (if applicable). The title, volume, cover year, and story name can often be found in small type at the bottom of the page opposite the inside cover. Directories should be named with the title of the series and the issue numbers. For example: ../Buffy the Vampire Slayer Season Eight - #01-#08/ and ../Amazing Spiderman - Volume 1 - #10-#20/ + +
    • +
    +
    + +

    5. eBooks, eLearning Books & Sheet Music

    +
    +
      + +
    • ↑_ 5.1. Individual releases can be either a torrent of a directory, an archive or original format (e.g. .chm, .pdf, .txt, etc.). Neither the individual release or archive can be password protected. +
    • +
    • ↑_ 5.2. Do not archive collections into a single archive (.zip, .tar, .rar, etc.). You may individually archive each release separately if you want to compress the files. Uploading a pack of eBooks in one archive (e.g. .tar, .rar, .zip) is prohibited. +
    • +
    • ↑_ 5.3. Only published eBooks are allowed. Freely available eBooks are not allowed. This rule also covers recipes and cookbooks: only official publications are allowed. +
    • + +
    • ↑_ 5.4. Collections of eBooks are allowed if each title is related to each other in a meaningful way. Releases of similar topic can be uploaded in a collection. You may not upload a collection of eBooks with nothing in common other than made by a single publisher (e.g. O'Reilly). Nor does it mean you can group eBooks by a broad area of topic. For example, "50 books in English," "Psychology books," or "Electrical engineering pack." Your collection must focus on a specific topic, series, or a body of work by an author. +
    • +
    • ↑_ 5.5. Identical eBooks and identical sheet music uploads are dupes respectively. The same eBook and sheet music titles in the same format (e.g. .pdf, .chm, .txt, etc.) are dupes. Exceptions: eBooks and sheet music uploaded individually are not dupes if the same eBooks or sheet music releases are part of a torrent that consists of a collection. +
    • + +
    • ↑_ 5.6. Include proper Gazelle tags for your eBook and sheet music uploads. You are strongly encouraged to use the appropriate default tags with your uploads. That way other users can find your uploads easily through the tag search system. Sheet music should use the sheet.music tag. eBooks should at least contain the tag ebooks.fiction or ebooks.non.fiction depending on the contents. You may add additional tags if the defaults do not apply or are not enough to describe the torrent contents. +
    • +
    +
    + +

    6. Comedy (Audio) & Audio Books

    + +
    +
      +
    • ↑_ 6.1. The only formats allowed for comedy and audio books are those listed below: +
        +
      • MP3, FLAC, Ogg Vorbis, AAC, AC3, DTS
      • +
      +

      Monkey's Audio (APE), Apple Lossless (ALAC/.M4A lossless), and Wavpack (WV) are deprecated. No more new uploads in either of these 3 formats are allowed after April 20, 2009. Only unique releases with no alternative upload in FLAC are permitted to remain on the site. However, you are encouraged to convert them to FLAC. +

      +
    • +
    • ↑_ 6.2. No music is permitted in these two categories. They are for spoken word only. +
    • +
    • ↑_ 6.3. No radio talk shows and podcasts are allowed. What.CD is primarily a music site, and those do not belong in any torrent categories. +
    • + +
    • ↑_ 6.4. Comedy and audio books must not be freely available. Free audio books and comedy releases from official sources may not be uploaded. Exceptions: Uploads that are at a different bitrate from those freely available are allowed. If a comedy album in 96kbps CBR MP3 is freely available, you may still upload a -V8 (VBR) or higher bitrate torrent of the freely available torrent if it does not exist on the site already. +
    • +
    • ↑_ 6.5. Releases must be unarchived and of a single release. Comedy and audio book releases should not be archived in a file, such as .zip or .rar. Releases must be a torrent of a directory containing the audio files. Only one torrent per release. You may not bundle multiple audio books or comedy releases in one torrent. See 1.2.7. + +
    • +
    • ↑_ 6.6. All comedy and audio book releases must at least have an average bitrate of 16kbps mono or 32kbps stereo. Higher bitrates are preferred over this minimum, however. +
    • +
    • ↑_ 6.7. Lossy sources, including lossy transcodes, are allowed in this section only. Lossy-sourced audio is permitted only in the comedy and audio book categories. This means the source may come from cassette, VHS (audio), radio, or a higher bitrate lossy file. While the sharing of transcoded material is strongly discouraged for music, the audio quality is less important for spoken word material. You may not transcode a lower bitrate file to a higher bitrate file and upload here. For example, you find a 32kbps CBR WMA and transcode it to 64kbps CBR MP3. +
    • + +
    • ↑_ 6.8. Duplicate torrents of the same bitrate and format are not allowed. No uploads of the same bitrate and format are allowed to coexist on the site. For example, if a torrent exists on the site in 256kbps MP3, no further torrents in 256kbps MP3 are allowed. Significantly higher or lower bitrate rips or different file formats of the same content are allowed. Exceptions: One LAME -V8 (or -V8 --vbr-new [with or without -mm]) rip is allowed on the site at any time. Even if a 85kbps CBR rip is already on the site, you may still upload a -V8 (VBR). The -V8 (VBR) may be sourced from a higher bitrate lossy encoded file. +
    • +
    • ↑_ 6.9. Scene and non-scene releases of the same release, bitrate, and format are dupes. The "scene" label does not make torrents unique from each other. If a -V2 (VBR) of an album in CD is already uploaded, you may not upload a -V2 (VBR) scene version of the same album in CD. +
    • + +
    • ↑_ 6.10. Releases must follow formatting guidelines for file names and tags. Audiobooks and comedy must follow formatting rules outlined in section 2.3. This means no file names without track numbers, no files without metatags, and so forth. For comedy, at least use the official Gazelle tag of "comedy". And for audio books, at least use the Gazelle tag of "audio.books". +
    • +
    +
    + + +

    7. eLearning Videos

    +
    +
      +
    • ↑_ 7.1. The eLearning Videos category is for tutorial videos of specific topics only. Any video clips mentioned in Section 1.2. cannot be uploaded to the eLearning Videos category. +
    • + +
    • ↑_ 7.2. No freely available eLearning videos You may not upload videos hosted officially from university sites, the author's site, the Internet Archive or publisher's site. You may upload videos from other torrent sites provided they conform to the rules in this section. +
    • +
    • ↑_ 7.3. Tutorials on how to use musical instruments, vocal training, producing music or otherwise learning the theory and practice of music are the only allowed topics. No material outside of these topics is allowed. For example, instruction videos about Kung Fu training, dance lessons, beer brewing or photography are not permitted here. What is considered allowed under these topics is ultimately under staff discretion. +
    • + +
    • ↑_ 7.4. eLearning Videos must be either in a video file format (.mkv, .avi, .mov, .mp4 etc.) or a disk image (.iso, .bin/.cue, etc.). Only one video file format and one disk image format are allowed per video, anything else is a dupe. Torrents should not be uploaded in compressed archives. +
    • +
    • ↑_ 7.5. eLearning video uploads must contain an informative description and use proper Gazelle tags. Uploads should include a proper description and/or a link to further information. It is strongly encouraged they at least have the elearning.videos Gazelle tag as well. +
    • + +
    +
    +
    + + + +
    + diff --git a/sections/schedule/index.php b/sections/schedule/index.php new file mode 100644 index 00000000..5ca188b4 --- /dev/null +++ b/sections/schedule/index.php @@ -0,0 +1,1028 @@ +=8) { + $Return = 22; + } else { + $Return = 8; + } + return $Return; +} + +function next_day() { + $Tomorrow = time(0,0,0,date('m'),date('d')+1,date('Y')); + return date('d', $Tomorrow); +} + +function next_hour() { + $Hour = time(date('H')+1,0,0,date('m'),date('d'),date('Y')); + return date('H', $Hour); +} + +if ((!isset($argv[1]) || $argv[1]!=SCHEDULE_KEY) && !check_perms('admin_schedule')) { // authorization, Fix to allow people with perms hit this page. + error(403); +} + +if (check_perms('admin_schedule')) { + authorize(); + show_header(); + echo '
    ';
    +}
    +
    +$DB->query("SELECT NextHour, NextDay, NextBiWeekly FROM schedule");
    +list($Hour, $Day, $BiWeek) = $DB->next_record();
    +$DB->query("UPDATE schedule SET NextHour = ".next_hour().", NextDay = ".next_day().", NextBiWeekly = ".next_biweek());
    +
    +$sqltime = sqltime();
    +
    +echo "$sqltime\n";
    +
    +
    +
    +/*************************************************************************\
    +//--------------Run every time ------------------------------------------//
    +
    +These functions are run every time the script is executed (every 15
    +minutes).
    +
    +\*************************************************************************/
    +
    +
    +echo "Ran every-time functions\n";
    +
    +//------------- Freeleech -----------------------------------------------//
    +
    +//We use this to control 6 hour freeleeches. They're actually 7 hour, but don't tell anyone. 
    +/*
    +$TimeMinus = time_minus(3600*7);
    +
    +$DB->query("SELECT DISTINCT GroupID FROM torrents WHERE FreeTorrent='1' AND FreeLeechType='3' AND Time<'$TimeMinus'");
    +while(list($GroupID) = $DB->next_record()) {
    +	$Cache->delete_value('torrents_details_'.$GroupID);
    +	$Cache->delete_value('torrent_group_'.$GroupID);
    +}
    +$DB->query("UPDATE torrents SET FreeTorrent='0',FreeLeechType='0',flags='2' WHERE FreeTorrent='1' AND FreeLeechType='3' AND Time<'$TimeMinus'");
    +*/
    +sleep(5);
    +//------------- Delete unpopular tags -----------------------------------//
    +$DB->query("DELETE FROM torrents_tags WHERE NegativeVotes>PositiveVotes");
    +
    +//------------- Expire old FL Tokens and clear cache where needed ------//
    +$sqltime = sqltime();
    +$DB->query("SELECT DISTINCT UserID from users_freeleeches WHERE Expired = FALSE AND Time < '$sqltime' - INTERVAL 4 DAY");
    +while (list($UserID) = $DB->next_record()) {
    +	$Cache->delete_value('users_tokens_'.$UserID[0]);
    +}
    +
    +$DB->query("SELECT uf.UserID, t.info_hash 
    +            FROM users_freeleeches AS uf 
    +            JOIN torrents AS t ON uf.TorrentID = t.ID
    +			WHERE uf.Expired = FALSE AND uf.Time < '$sqltime' - INTERVAL 4 DAY");
    +while (list($UserID,$InfoHash) = $DB->next_record(MYSQLI_NUM, false)) {
    +	update_tracker('remove_token', array('info_hash' => rawurlencode($InfoHash), 'userid' => $UserID));
    +}
    +$DB->query("UPDATE users_freeleeches SET Expired = True WHERE Time < '$sqltime' - INTERVAL 4 DAY");
    +
    +
    +
    +
    +/*************************************************************************\
    +//--------------Run every hour ------------------------------------------//
    +
    +These functions are run every hour.
    +
    +\*************************************************************************/
    +
    +
    +if($Hour != next_hour() || $_GET['runhour'] || isset($argv[2])){
    +	echo "Ran hourly functions\n";
    +	
    +	//------------- Front page stats ----------------------------------------//
    +
    +	//Love or hate, this makes things a hell of a lot faster
    +
    +	if ($Hour%2 == 0) {
    +		$DB->query("SELECT COUNT(uid) AS Snatches FROM xbt_snatched");
    +		list($SnatchStats) = $DB->next_record();
    +		$Cache->cache_value('stats_snatches',$SnatchStats,0);
    +	}
    +
    +	$DB->query("SELECT IF(remaining=0,'Seeding','Leeching') AS Type, COUNT(uid) FROM xbt_files_users WHERE active=1 GROUP BY Type");
    +	$PeerCount = $DB->to_array(0, MYSQLI_NUM, false);
    +	$SeederCount = isset($PeerCount['Seeding'][1]) ? $PeerCount['Seeding'][1] : 0;
    +	$LeecherCount = isset($PeerCount['Leeching'][1]) ? $PeerCount['Leeching'][1] : 0;
    +	$Cache->cache_value('stats_peers',array($LeecherCount,$SeederCount),0);
    +
    +	$DB->query("SELECT COUNT(ID) FROM users_main WHERE Enabled='1' AND LastAccess>'".time_minus(3600*24)."'");
    +	list($UserStats['Day']) = $DB->next_record();
    +
    +	$DB->query("SELECT COUNT(ID) FROM users_main WHERE Enabled='1' AND LastAccess>'".time_minus(3600*24*7)."'");
    +	list($UserStats['Week']) = $DB->next_record();
    +
    +	$DB->query("SELECT COUNT(ID) FROM users_main WHERE Enabled='1' AND LastAccess>'".time_minus(3600*24*30)."'");
    +	list($UserStats['Month']) = $DB->next_record();
    +
    +	$Cache->cache_value('stats_users',$UserStats,0);
    +	
    +	//------------- Record who's seeding how much, used for ratio watch
    +	
    +	$DB->query("TRUNCATE TABLE users_torrent_history_temp");
    +	$DB->query("INSERT INTO users_torrent_history_temp 
    +		(UserID, NumTorrents) 
    +		SELECT uid, 
    +		COUNT(DISTINCT fid) 
    +		FROM xbt_files_users 
    +		WHERE mtime>unix_timestamp(now()-interval 1 hour) 
    +		AND Remaining=0
    +		GROUP BY uid;");
    +	$DB->query("UPDATE users_torrent_history AS h 
    +		JOIN users_torrent_history_temp AS t ON t.UserID=h.UserID AND t.NumTorrents=h.NumTorrents 
    +		SET h.Finished='0', 
    +		h.LastTime=unix_timestamp(now()) 
    +		WHERE h.Finished='1' 
    +		AND h.Date=UTC_DATE()+0;");
    +	$DB->query("INSERT INTO users_torrent_history
    +		(UserID, NumTorrents, Date)
    +		SELECT UserID, NumTorrents, UTC_DATE()+0
    +		FROM users_torrent_history_temp
    +		ON DUPLICATE KEY UPDATE
    +		Time=Time+(unix_timestamp(NOW())-LastTime),
    +		LastTime=unix_timestamp(NOW());");
    +
    +	//------------- Promote users -------------------------------------------//
    +	sleep(5);
    +	$Criteria = array();
    +	$Criteria[]=array('From'=>USER, 'To'=>MEMBER, 'MinUpload'=>10*1024*1024*1024, 'MinRatio'=>0.7, 'MinUploads'=>0, 'MaxTime'=>time_minus(3600*24*7));
    +	$Criteria[]=array('From'=>MEMBER, 'To'=>POWER, 'MinUpload'=>25*1024*1024*1024, 'MinRatio'=>1.05, 'MinUploads'=>5, 'MaxTime'=>time_minus(3600*24*7*2));
    +	$Criteria[]=array('From'=>POWER, 'To'=>ELITE, 'MinUpload'=>100*1024*1024*1024, 'MinRatio'=>1.05, 'MinUploads'=>50, 'MaxTime'=>time_minus(3600*24*7*4));
    +	$Criteria[]=array('From'=>ELITE, 'To'=>TORRENT_MASTER, 'MinUpload'=>500*1024*1024*1024, 'MinRatio'=>1.05, 'MinUploads'=>500, 'MaxTime'=>time_minus(3600*24*7*8));
    +	$Criteria[]=array('From'=>TORRENT_MASTER, 'To'=>POWER_TM, 'MinUpload'=>500*1024*1024*1024, 'MinRatio'=>1.05, 'MinUploads'=>500, 'MaxTime'=>time_minus(3600*24*7*8), 'Extra'=>'(SELECT COUNT(DISTINCT GroupID) FROM torrents WHERE UserID=users_main.ID) >= 500');
    +	$Criteria[]=array('From'=>24, 'To'=>25, 'MinUpload'=>500*1024*1024*1024, 'MinRatio'=>1.05, 'MinUploads'=>500, 'MaxTime'=>time_minus(3600*24*7*8), 'Extra'=>"(SELECT COUNT(ID) FROM torrents WHERE ((LogScore = 100 AND Format = 'FLAC') OR (Media = 'Vinyl' AND Format = 'FLAC') OR (Media = 'WEB' AND Format = 'FLAC') OR (Media = 'DVD' AND Format = 'FLAC') OR (Media = 'Soundboard' AND Format = 'FLAC') OR (Media = 'Cassette' AND Format = 'FLAC') OR (Media = 'SACD' AND Format = 'FLAC') OR (Media = 'Blu-ray' AND Format = 'FLAC') OR (Media = 'DAT' AND Format = 'FLAC')) AND UserID = users_main.ID) >= 500");
    +
    +	 foreach($Criteria as $L){ // $L = Level
    +		$Query = "SELECT ID FROM users_main JOIN users_info ON users_main.ID = users_info.UserID
    +                        WHERE PermissionID=".$L['From']."
    +                        AND Warned= '0000-00-00 00:00:00'
    +                        AND Uploaded>='$L[MinUpload]'
    +                        AND (Uploaded/Downloaded >='$L[MinRatio]' OR (Uploaded/Downloaded IS NULL))
    +                        AND JoinDate<'$L[MaxTime]'
    +                        AND (SELECT COUNT(ID) FROM torrents WHERE UserID=users_main.ID)>='$L[MinUploads]'
    +                        AND Enabled='1'";
    +		if (!empty($L['Extra'])) {
    +			$Query .= ' AND '.$L['Extra'];
    +		}
    +		
    +		$DB->query($Query);
    +
    +		$UserIDs = $DB->collect('ID');
    +
    +		if (count($UserIDs) > 0) {
    +			foreach($UserIDs as $UserID) {
    +				/*$Cache->begin_transaction('user_info_'.$UserID);
    +				$Cache->update_row(false, array('PermissionID'=>$L['To']));
    +				$Cache->commit_transaction(0);*/
    +				$Cache->delete_value('user_info_'.$UserID);
    +				$Cache->delete_value('user_info_heavy_'.$UserID);
    +				$Cache->delete_value('user_stats_'.$UserID);
    +				$Cache->delete_value('enabled_'.$UserID);
    +				$DB->query("UPDATE users_info SET AdminComment = CONCAT('".sqltime()." - Class changed to ".make_class_string($L['To'])." by System\n\n', AdminComment) WHERE UserID = ".$UserID);
    +			}		
    +			$DB->query("UPDATE users_main SET PermissionID=".$L['To']." WHERE ID IN(".implode(',',$UserIDs).")");
    +		}
    +
    +		// Demote users with less than the required uploads
    +		
    +		$Query = "SELECT ID FROM users_main JOIN users_info ON users_main.ID = users_info.UserID
    +			WHERE PermissionID='$L[To]'
    +			AND ( Uploaded<'$L[MinUpload]'
    +			OR (SELECT COUNT(ID) FROM torrents WHERE UserID=users_main.ID)<'$L[MinUploads]'";
    +			if (!empty($L['Extra'])) {
    +				$Query .= " OR NOT ".$L['Extra'];
    +			}
    +			$Query .= ")
    +			AND Enabled='1'
    +			AND ID NOT IN (213461)";
    +		
    +		$DB->query($Query);
    +		$UserIDs = $DB->collect('ID');
    +		
    +		if (count($UserIDs) > 0) {
    +			foreach($UserIDs as $UserID) {
    +				/*$Cache->begin_transaction('user_info_'.$UserID);
    +				$Cache->update_row(false, array('PermissionID'=>$L['From']));
    +				$Cache->commit_transaction(0);*/
    +				$Cache->delete_value('user_info_'.$UserID);
    +				$Cache->delete_value('user_info_heavy_'.$UserID);
    +				$Cache->delete_value('user_stats_'.$UserID);
    +				$Cache->delete_value('enabled_'.$UserID);
    +				$DB->query("UPDATE users_info SET AdminComment = CONCAT('".sqltime()." - Class changed to ".make_class_string($L['From'])." by System\n\n', AdminComment) WHERE UserID = ".$UserID);
    +			}
    +			$DB->query("UPDATE users_main SET PermissionID=".$L['From']." WHERE ID IN(".implode(',',$UserIDs).")");
    +		}
    +	}
    +
    +
    +	//------------- Expire invites ------------------------------------------//
    +	sleep(3);
    +	$DB->query("SELECT InviterID FROM invites WHERE Expires<'$sqltime'");
    +	$Users = $DB->to_array();
    +	foreach ($Users as $UserID) {
    +		list($UserID) = $UserID;
    +		$DB->query("SELECT Invites FROM users_main WHERE ID=$UserID");
    +		list($Invites) = $DB->next_record();
    +		if ($Invites < 10) {
    +			$DB->query("UPDATE users_main SET Invites=Invites+1 WHERE ID=$UserID");
    +			$Cache->begin_transaction('user_info_heavy_'.$UserID);
    +			$Cache->update_row(false, array('Invites' => '+1'));
    +			$Cache->commit_transaction(0);
    +		}
    +	}
    +	$DB->query("DELETE FROM invites WHERE Expires<'$sqltime'");
    +
    +
    +	//------------- Hide old requests ---------------------------------------//
    +	sleep(3);
    +	$DB->query("UPDATE requests SET Visible = 0 WHERE TimeFilled < (NOW() - INTERVAL 7 DAY) AND TimeFilled <> '0000-00-00 00:00:00'");
    +
    +	//------------- Remove dead peers ---------------------------------------//
    +	sleep(3);
    +	$DB->query("DELETE FROM xbt_files_users WHERE mtimequery("SELECT UserID, SessionID FROM users_sessions WHERE Active = 1 AND LastUpdate<'$AgoDays' AND KeepLogged='1'");
    +	while(list($UserID,$SessionID) = $DB->next_record()) {
    +		$Cache->begin_transaction('users_sessions_'.$UserID);
    +		$Cache->delete_row($SessionID);
    +		$Cache->commit_transaction(0);
    +	}
    +	
    +	
    +	$DB->query("DELETE FROM users_sesions WHERE LastUpdate<'$AgoDays' AND KeepLogged='1'");
    +	
    +	
    +	$AgoMins = time_minus(60*30);
    +	$DB->query("SELECT UserID, SessionID FROM users_sessions WHERE Active = 1 AND LastUpdate<'$AgoMins' AND KeepLogged='0'");
    +	while(list($UserID,$SessionID) = $DB->next_record()) {
    +		$Cache->begin_transaction('users_sessions_'.$UserID);
    +		$Cache->delete_row($SessionID);
    +		$Cache->commit_transaction(0);
    +	}
    +	
    +	
    +	$DB->query("DELETE FROM users_sessions WHERE LastUpdate<'$AgoMins' AND KeepLogged='0'");
    +	
    +
    +	
    +	//------------- Lower Login Attempts ------------------------------------//
    +	$DB->query("UPDATE login_attempts SET Attempts=Attempts-1 WHERE Attempts>0");
    +	$DB->query("DELETE FROM login_attempts WHERE LastAttempt<'".time_minus(3600*24*90)."'");
    +
    +        //------------- Remove expired warnings ---------------------------------//
    +        $DB->query("SELECT UserID FROM users_info WHERE Warned<'$sqltime'");
    +        while(list($UserID) = $DB->next_record()) {
    +                $Cache->begin_transaction('user_info_'.$UserID);
    +                $Cache->update_row(false, array('Warned'=>'0000-00-00 00:00:00'));
    +                $Cache->commit_transaction(2592000);
    +        }
    +
    +        $DB->query("UPDATE users_info SET Warned='0000-00-00 00:00:00' WHERE Warned<'$sqltime'");
    +
    +	// If a user has downloaded more than 10 gigs while on ratio watch, banhammer
    +
    +        $DB->query("SELECT ID FROM users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +                WHERE i.RatioWatchEnds!='0000-00-00 00:00:00'
    +                AND i.RatioWatchDownload+10*1024*1024*1024collect('ID');
    +        if(count($UserIDs) > 0) {
    +                disable_users($UserIDs, "Disabled by ratio watch system for downloading more than 10 gigs on ratio watch.", 2);
    +        }
    +
    +}
    +/*************************************************************************\
    +//--------------Run every day -------------------------------------------//
    +
    +These functions are run in the first 15 minutes of every day.
    +
    +\*************************************************************************/
    +
    +if($Day != next_day() || $_GET['runday']){
    +	echo "Ran daily functions\n";
    +	if($Day%2 == 0) { // If we should generate the drive database (at the end)
    +		$GenerateDriveDB = true;
    +	}
    +	
    +	//------------- Ratio requirements
    +	
    +	
    +	$DB->query("DELETE FROM users_torrent_history WHERE Datequery("TRUNCATE TABLE users_torrent_history_temp;");
    +	$DB->query("INSERT INTO users_torrent_history_temp 
    +		(UserID, SumTime)
    +		SELECT UserID, SUM(Time) FROM users_torrent_history
    +		GROUP BY UserID;");
    +	$DB->query("INSERT INTO users_torrent_history
    +		(UserID, NumTorrents, Date, Time)
    +		SELECT UserID, 0, UTC_DATE()+0, 259200-SumTime
    +		FROM users_torrent_history_temp
    +		WHERE SumTime<259200;");
    +	$DB->query("UPDATE users_torrent_history SET Weight=NumTorrents*Time;");
    +	$DB->query("TRUNCATE TABLE users_torrent_history_temp;");
    +	$DB->query("INSERT INTO users_torrent_history_temp 
    +		(UserID, SeedingAvg)
    +		SELECT UserID, SUM(Weight)/SUM(Time) FROM users_torrent_history
    +		GROUP BY UserID;");
    +	$DB->query("DELETE FROM users_torrent_history WHERE NumTorrents='0'");
    +	$DB->query("TRUNCATE TABLE users_torrent_history_snatch;");
    +	$DB->query("INSERT INTO users_torrent_history_snatch(UserID, NumSnatches) 
    +		SELECT 
    +		xs.uid,
    +		COUNT(DISTINCT xs.fid)
    +		FROM
    +		xbt_snatched AS xs
    +		join torrents on torrents.ID=xs.fid
    +		GROUP BY xs.uid;");
    +	$DB->query("UPDATE users_main AS um
    +		JOIN users_torrent_history_temp AS t ON t.UserID=um.ID
    +		JOIN users_torrent_history_snatch AS s ON s.UserID=um.ID
    +		SET um.RequiredRatioWork=(1-(t.SeedingAvg/s.NumSnatches))
    +		WHERE s.NumSnatches>0;");
    +	
    +	$RatioRequirements = array(
    +		array(80*1024*1024*1024, 0.60, 0.50),
    +		array(60*1024*1024*1024, 0.60, 0.40),
    +		array(50*1024*1024*1024, 0.60, 0.30),
    +		array(40*1024*1024*1024, 0.50, 0.20),
    +		array(30*1024*1024*1024, 0.40, 0.10),
    +		array(20*1024*1024*1024, 0.30, 0.05),
    +		array(10*1024*1024*1024, 0.20, 0.0),
    +		array(5*1024*1024*1024,  0.15, 0.0)
    +	);
    +	
    +	$DB->query("UPDATE users_main SET RequiredRatio=0.60 WHERE Downloaded>100*1024*1024*1024");
    +	
    +	
    +	
    +	$DownloadBarrier = 100*1024*1024*1024;
    +	foreach($RatioRequirements as $Requirement) {
    +		list($Download, $Ratio, $MinRatio) = $Requirement;
    +		
    +		$DB->query("UPDATE users_main SET RequiredRatio=RequiredRatioWork*$Ratio WHERE Downloaded >= '$Download' AND Downloaded < '$DownloadBarrier'");
    +		
    +		$DB->query("UPDATE users_main SET RequiredRatio=$MinRatio WHERE Downloaded >= '$Download' AND Downloaded < '$DownloadBarrier' AND RequiredRatio<$MinRatio");
    +		
    +		$DB->query("UPDATE users_main SET RequiredRatio=$Ratio WHERE Downloaded >= '$Download' AND Downloaded < '$DownloadBarrier' AND can_leech='0' AND Enabled='1'");
    +		
    +		$DownloadBarrier = $Download;
    +	}
    +	
    +	$DB->query("UPDATE users_main SET RequiredRatio=0.00 WHERE Downloaded<5*1024*1024*1024");
    +	
    +	// Here is where we manage ratio watch
    +	
    +	$OffRatioWatch = array();
    +	$OnRatioWatch = array();
    +	
    +	// Take users off ratio watch and enable leeching
    +	$UserQuery = $DB->query("SELECT m.ID, torrent_pass FROM users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +		WHERE m.Uploaded/m.Downloaded >= m.RequiredRatio
    +		AND i.RatioWatchEnds!='0000-00-00 00:00:00' 
    +		AND m.can_leech='0'
    +		AND m.Enabled='1'");
    +	$OffRatioWatch = $DB->collect('ID');
    +	if(count($OffRatioWatch)>0) {
    +		$DB->query("UPDATE users_info AS ui
    +			JOIN users_main AS um ON um.ID = ui.UserID
    +			SET ui.RatioWatchEnds='0000-00-00 00:00:00',
    +			ui.RatioWatchDownload='0',
    +			um.can_leech='1',
    +			ui.AdminComment = CONCAT('".$sqltime." - Leeching re-enabled by adequate ratio.\n\n', ui.AdminComment)
    +			WHERE ui.UserID IN(".implode(",", $OffRatioWatch).")");
    +	}
    +	
    +	foreach($OffRatioWatch as $UserID) {
    +		$Cache->begin_transaction('user_info_heavy_'.$UserID);
    +		$Cache->update_row(false, array('RatioWatchEnds'=>'0000-00-00 00:00:00','RatioWatchDownload'=>'0','CanLeech'=>1));
    +		$Cache->commit_transaction(0);
    +		send_pm($UserID, 0, db_string("You have been taken off Ratio Watch"), db_string("Congratulations! Feel free to begin downloading again.\n To ensure that you do not get put on ratio watch again, please read the rules located [url=http://".NONSSL_SITE_URL."/rules.php?p=ratio]here[/url].\n"), '');
    +		echo "Ratio watch off: $UserID\n";
    +	}
    +	$DB->set_query_id($UserQuery);
    +	$Passkeys = $DB->collect('torrent_pass');
    +	foreach($Passkeys as $Passkey) {
    +		update_tracker('update_user', array('passkey' => $Passkey, 'can_leech' => '1'));
    +	}
    +
    +        // Take users off ratio watch 
    +        $UserQuery = $DB->query("SELECT m.ID, torrent_pass FROM users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +                WHERE m.Uploaded/m.Downloaded >= m.RequiredRatio
    +                AND i.RatioWatchEnds!='0000-00-00 00:00:00'
    +                AND m.Enabled='1'");
    +        $OffRatioWatch = $DB->collect('ID');
    +        if(count($OffRatioWatch)>0) {
    +                $DB->query("UPDATE users_info AS ui
    +                        JOIN users_main AS um ON um.ID = ui.UserID
    +                        SET ui.RatioWatchEnds='0000-00-00 00:00:00',
    +                        ui.RatioWatchDownload='0',
    +                        um.can_leech='1'
    +                        WHERE ui.UserID IN(".implode(",", $OffRatioWatch).")");
    +        }
    +
    +        foreach($OffRatioWatch as $UserID) {
    +                $Cache->begin_transaction('user_info_heavy_'.$UserID);
    +                $Cache->update_row(false, array('RatioWatchEnds'=>'0000-00-00 00:00:00','RatioWatchDownload'=>'0','CanLeech'=>1));
    +                $Cache->commit_transaction(0);
    +                send_pm($UserID, 0, db_string("You have been taken off Ratio Watch"), db_string("Congratulations! Feel free to begin downloading again.\n To ensure that you do not get put on ratio watch again, please read the rules located [url=http://".NONSSL_SITE_URL."/rules.php?p=ratio]here[/url].\n"), '');
    +                echo "Ratio watch off: $UserID\n";
    +        }
    +        $DB->set_query_id($UserQuery);
    +        $Passkeys = $DB->collect('torrent_pass');
    +        foreach($Passkeys as $Passkey) {
    +                update_tracker('update_user', array('passkey' => $Passkey, 'can_leech' => '1'));
    +        }
    +
    +	
    +	// Put user on ratio watch if he doesn't meet the standards
    +	sleep(10);
    +	$DB->query("SELECT m.ID, m.Downloaded FROM users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +		WHERE m.Uploaded/m.Downloaded < m.RequiredRatio
    +		AND i.RatioWatchEnds='0000-00-00 00:00:00'
    +		AND m.Enabled='1'
    +		AND m.can_leech='1'");
    +	$OnRatioWatch = $DB->collect('ID');
    +	
    +	if(count($OnRatioWatch)>0) {
    +		$DB->query("UPDATE users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +			SET i.RatioWatchEnds='".time_plus(60*60*24*14)."',
    +			i.RatioWatchTimes = i.RatioWatchTimes+1,
    +			i.RatioWatchDownload = m.Downloaded
    +			WHERE m.ID IN(".implode(",", $OnRatioWatch).")");
    +	}
    +	
    +	foreach($OnRatioWatch as $UserID) {
    +		$Cache->begin_transaction('user_info_heavy_'.$UserID);
    +		$Cache->update_row(false, array('RatioWatchEnds'=>time_plus(60*60*24*14),'RatioWatchDownload'=>0));
    +		$Cache->commit_transaction(0);
    +		send_pm($UserID, 0, db_string("You have been put on Ratio Watch"), db_string("This happens when your ratio falls below the requirements we have outlined in the rules located [url=http://".NONSSL_SITE_URL."/rules.php?p=ratio]here[/url].\n For information about ratio watch, click the link above."), '');
    +		echo "Ratio watch on: $UserID\n";
    +	}
    +
    +	sleep(5);
    +
    +	//------------- Rescore 0.95 logs of disabled users
    +
    +	$LogQuery = $DB->query("SELECT DISTINCT t.ID FROM torrents AS t JOIN users_main AS um ON t.UserID = um.ID JOIN torrents_logs_new AS tl ON tl.TorrentID = t.ID WHERE um.Enabled = '2' and t.HasLog = '1' and LogScore = 100 and Log LIKE 'EAC extraction logfile from%'");
    +	$Details = array();
    +	$Details[] = "Ripped with EAC v0.95, -1 point [1]";
    +	$Details = serialize($Details);
    +	while (list($TorrentID) = $DB->next_record()) {
    +		$DB->query("UPDATE torrents SET LogScore = 99 WHERE ID = ".$TorrentID);
    +		$DB->query("UPDATE torrents_logs_new SET Score = 99, Details = '".$Details."' WHERE TorrentID = ".$TorrentID);
    +	}
    +
    +	sleep(5);
    +	
    +	//------------- Disable downloading ability of users on ratio watch
    +	
    +	
    +	$UserQuery = $DB->query("SELECT ID, torrent_pass FROM users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +		WHERE i.RatioWatchEnds!='0000-00-00 00:00:00'
    +		AND i.RatioWatchEnds<'$sqltime'
    +		AND m.Enabled='1'
    +		AND m.can_leech!='0'");
    +	
    +	$UserIDs = $DB->collect('ID');
    +	if(count($UserIDs) > 0) {
    +		$DB->query("UPDATE users_info AS i JOIN users_main AS m ON m.ID=i.UserID
    +			SET 
    +			m.can_leech='0',
    +			i.AdminComment=CONCAT('$sqltime - Leeching ability disabled by ratio watch system - required ratio: ', m.RequiredRatio,'
    +
    +'			, i.AdminComment)
    +			WHERE m.ID IN(".implode(',',$UserIDs).")");
    +	}
    +	
    +	foreach($UserIDs as $UserID) {
    +		$Cache->begin_transaction('user_info_heavy_'.$UserID);
    +		$Cache->update_row(false, array('RatioWatchDownload'=>0, 'CanLeech'=>0));
    +		$Cache->commit_transaction(0);
    +		send_pm($UserID, 0, db_string("Your downloading rights have been disabled"), db_string("As you did not raise your ratio in time, your downloading rights have been revoked. You will not be able to download any torrents until your ratio is above your new required ratio."), '');
    +		echo "Ratio watch disabled: $UserID\n";
    +	}
    +
    +	$DB->set_query_id($UserQuery);
    +	$Passkeys = $DB->collect('torrent_pass');
    +	foreach($Passkeys as $Passkey) {
    +		update_tracker('update_user', array('passkey' => $Passkey, 'can_leech' => '0'));
    +	}
    +	
    +	//------------- Disable inactive user accounts --------------------------//
    +	sleep(5);
    +	// Send email
    +	$DB->query("SELECT um.Username, um.Email FROM  users_info AS ui JOIN users_main AS um ON um.ID=ui.UserID
    +		WHERE um.PermissionID IN ('".USER."', '".MEMBER	."')
    +		AND um.LastAccess<'".time_minus(3600*24*110, true)."'
    +		AND um.LastAccess>'".time_minus(3600*24*111, true)."'
    +		AND um.LastAccess!='0000-00-00 00:00:00'
    +		AND ui.Donor='0'
    +		AND um.Enabled!='2'");
    +	while(list($Username, $Email) = $DB->next_record()) {
    +		$Body = "Hi $Username, \n\nIt has been almost 4 months since you used your account at http://".NONSSL_SITE_URL.". This is an automated email to inform you that your account will be disabled in 10 days if you do not sign in. ";
    +		send_email($Email, 'Your '.SITE_NAME.' account is about to be disabled', $Body);
    +	}
    +	$DB->query("SELECT um.ID FROM  users_info AS ui JOIN users_main AS um ON um.ID=ui.UserID
    +		WHERE um.PermissionID IN ('".USER."', '".MEMBER	."')
    +		AND um.LastAccess<'".time_minus(3600*24*30*4)."' 
    +		AND um.LastAccess!='0000-00-00 00:00:00'
    +		AND ui.Donor='0'
    +		AND um.Enabled!='2'");
    +
    +	if($DB->record_count() > 0) {
    +		disable_users($DB->collect('ID'), "Disabled for inactivity.", 3);
    +	}
    +
    +	//------------- Disable unconfirmed users ------------------------------//
    +	sleep(10);
    +	$DB->query("UPDATE users_info AS ui JOIN users_main AS um ON um.ID=ui.UserID
    +		SET um.Enabled='2',
    +		ui.BanDate='$sqltime',
    +		ui.BanReason='3',
    +		ui.AdminComment=CONCAT('$sqltime - Disabled for inactivity (never logged in)
    +
    +', ui.AdminComment)
    +		WHERE um.LastAccess='0000-00-00 00:00:00'
    +		AND ui.JoinDate<'".time_minus(60*60*24*7)."'
    +		AND um.Enabled!='2'
    +		");
    +	$Cache->decrement('stats_user_count',$DB->affected_rows());
    +	
    +	echo "disabled unconfirmed\n";
    +	
    +	//------------- Demote users --------------------------------------------//
    +	sleep(10);
    +	$DB->query('SELECT um.ID FROM users_main AS um WHERE PermissionID IN('.POWER.', '.ELITE.', '.TORRENT_MASTER.') AND Uploaded/Downloaded < 0.95 OR PermissionID IN('.POWER.', '.ELITE.', '.TORRENT_MASTER.') AND Uploaded < 25*1024*1024*1024');
    +	
    +	echo "demoted 1\n";
    +	
    +	while(list($UserID) = $DB->next_record()) {
    +		$Cache->begin_transaction('user_info_'.$UserID);
    +		$Cache->update_row(false, array('PermissionID'=>MEMBER));
    +		$Cache->commit_transaction(2592000);
    +	}
    +	$DB->query('UPDATE users_main SET PermissionID='.MEMBER.' WHERE PermissionID IN('.POWER.', '.ELITE.', '.TORRENT_MASTER.') AND Uploaded/Downloaded < 0.95 OR PermissionID IN('.POWER.', '.ELITE.', '.TORRENT_MASTER.') AND Uploaded < 25*1024*1024*1024');
    +	echo "demoted 2\n";
    +	
    +	$DB->query('SELECT um.ID FROM users_main AS um WHERE PermissionID IN('.MEMBER.', '.POWER.', '.ELITE.', '.TORRENT_MASTER.') AND Uploaded/Downloaded < 0.65');
    +	echo "demoted 3\n";
    +	while(list($UserID) = $DB->next_record()) {
    +		$Cache->begin_transaction('user_info_'.$UserID);
    +		$Cache->update_row(false, array('PermissionID'=>USER));
    +		$Cache->commit_transaction(2592000);
    +	}
    +	$DB->query('UPDATE users_main SET PermissionID='.USER.' WHERE PermissionID IN('.MEMBER.', '.POWER.', '.ELITE.', '.TORRENT_MASTER.') AND Uploaded/Downloaded < 0.65');
    +	echo "demoted 4\n";
    +
    +	//------------- Lock old threads ----------------------------------------//
    +	sleep(10);
    +	$DB->query("SELECT t.ID
    +				FROM forums_topics AS t
    +				JOIN forums AS f ON t.ForumID = f.ID
    +				WHERE t.IsLocked='0' AND t.IsSticky='0'
    +				  AND t.LastPostTime<'".time_minus(3600*24*28)."'
    +				  AND f.AutoLock = '1'");
    +	$IDs = $DB->collect('ID');
    +	
    +	if(count($IDs) > 0) {
    +		$LockIDs = implode(',', $IDs);
    +		$DB->query("UPDATE forums_topics SET IsLocked='1' WHERE ID IN($LockIDs)");
    +		sleep(2);
    +		$DB->query("DELETE FROM forums_last_read_topics WHERE TopicID IN($LockIDs)");
    +	
    +		foreach($IDs as $ID) {
    +			$Cache->begin_transaction('thread_'.$ID.'_info');
    +			$Cache->update_row(false, array('IsLocked'=>'1'));
    +			$Cache->commit_transaction(3600*24*30);
    +			$Cache->expire_value('thread_'.$TopicID.'_catalogue_0',3600*24*30);
    +			$Cache->expire_value('thread_'.$TopicID.'_info',3600*24*30);
    +		}
    +	}
    +	echo "Old threads locked\n";
    +
    +	//------------- Delete dead torrents ------------------------------------//
    +	
    +	sleep(10);
    +	//remove dead torrents that were never announced to -- XBTT will not delete those with a pid of 0, only those that belong to them (valid pids)
    +	
    +	$DB->query("DELETE FROM torrents WHERE flags = 1 AND pid = 0");
    +	sleep(10);
    +	
    +
    +
    +	$i = 0;
    +	$DB->query("SELECT
    +		t.ID,
    +		t.GroupID,
    +		tg.Name,
    +		ag.Name,
    +		t.last_action,
    +		t.Format,
    +		t.Encoding,
    +		t.UserID
    +		FROM torrents AS t
    +		JOIN torrents_group AS tg ON tg.ID = t.GroupID
    +		LEFT JOIN artists_group AS ag ON ag.ArtistID = tg.ArtistID
    +		WHERE t.last_action < '".time_minus(3600*24*28)."'
    +		AND t.last_action != 0
    +		OR t.Time < '".time_minus(3600*24*2)."'
    +		AND t.last_action = 0");
    +	$TorrentIDs = $DB->to_array();
    +	echo "Found ".count($TorrentIDs)." inactive torrents to be deleted.\n";
    +	
    +	$LogEntries = array();
    +	
    +	// Exceptions for inactivity deletion
    +	$InactivityExceptionsMade = array(//UserID => expiry time of exception
    +		
    +	);
    +	foreach ($TorrentIDs as $TorrentID) {
    +		list($ID, $GroupID, $Name, $ArtistName, $LastAction, $Format, $Encoding, $UserID, $Media) = $TorrentID;
    +		if (array_key_exists($UserID, $InactivityExceptionsMade) && (time() < $InactivityExceptionsMade[$UserID])) {
    +			// don't delete the torrent!
    +			continue;	
    +		}
    +		if($ArtistName) {
    +			$Name = $ArtistName.' - '.$Name;
    +		}
    +		if($Format && $Encoding) {
    +			$Name.=' ['.(empty($Media)?'':"$Media / ").$Format.' / '.$Encoding.']';
    +		}
    +		delete_torrent($ID, $GroupID);
    +		$LogEntries[] = "Torrent ".$ID." (".$Name.") was deleted for inactivity (unseeded)";
    +		
    +		if (!array_key_exists($UserID, $DeleteNotes))
    +				$DeleteNotes[$UserID] = array('Count' => 0, 'Msg' => '');
    +		
    +		$DeleteNotes[$UserID]['Msg'] .= "\n$Name";
    +		$DeleteNotes[$UserID]['Count']++;
    +		
    +		++$i;
    +		if ($i % 500 == 0) {
    +			echo "$i inactive torrents removed.\n";
    +		}
    +	}
    +	echo "$i torrents deleted for inactivity.\n";
    +	
    +	foreach($DeleteNotes as $UserID => $MessageInfo){
    +		$Singular = ($MessageInfo['Count'] == 1) ? true : false;
    +		send_pm($UserID,0,db_string($MessageInfo['Count'].' of your torrents '.($Singular?'has':'have').' been deleted for inactivity'), db_string(($Singular?'One':'Some').' of your uploads '.($Singular?'has':'have').' been deleted for being unseeded.  Since '.($Singular?'it':'they').' didn\'t break any rules (we hope), please feel free to re-upload '.($Singular?'it':'them').".\n\nThe following torrent".($Singular?' was':'s were').' deleted:'.$MessageInfo['Msg']));
    +	}	
    +	unset($DeleteNotes);
    +	
    +	if(count($LogEntries) > 0) {
    +		$Values = "('".implode("', '".$sqltime."'), ('",$LogEntries)."', '".$sqltime."')";
    +		$DB->query('INSERT INTO log (Message, Time) VALUES '.$Values);
    +		echo "\nDeleted $i torrents for inactivity\n";
    +	}
    +
    +	$DB->query("SELECT SimilarID FROM artists_similar_scores WHERE Score<=0");
    +	$SimilarIDs = implode(',',$DB->collect('SimilarID'));
    +	
    +	if($SimilarIDs) {	
    +		$DB->query("DELETE FROM artists_similar WHERE SimilarID IN($SimilarIDs)");
    +		$DB->query("DELETE FROM artists_similar_scores WHERE SimilarID IN($SimilarIDs)");
    +		$DB->query("DELETE FROM artists_similar_votes WHERE SimilarID IN($SimilarIDs)");
    +	}
    +	
    +	
    +
    +	// Daily top 10 history.
    +	$DB->query("INSERT INTO top10_history (Date, Type) VALUES ('".$sqltime."', 'Daily')");
    +	$HistoryID = $DB->inserted_id();
    +
    +	$Top10 = $Cache->get_value('top10tor_day_10');
    +	if($Top10 === false) {
    +		$DB->query("SELECT
    +				t.ID,
    +				g.ID,
    +				g.Name,
    +				g.CategoryID,
    +				g.TagList,
    +				t.Format,
    +				t.Encoding,
    +				t.Media,
    +				t.Scene,
    +				t.HasLog,
    +				t.HasCue,
    +				t.LogScore,
    +				t.RemasterYear,
    +				g.Year,
    +				t.RemasterTitle,
    +				t.Snatched,
    +				t.Seeders,
    +				t.Leechers,
    +				((t.Size * t.Snatched) + (t.Size * 0.5 * t.Leechers)) AS Data
    +			FROM torrents AS t
    +				LEFT JOIN torrents_group AS g ON g.ID = t.GroupID
    +			WHERE t.Seeders>0
    +				AND t.Time > ('".$sqltime."' - INTERVAL 1 DAY)
    +			ORDER BY (t.Seeders + t.Leechers) DESC
    +				LIMIT 10;");
    +
    +		$Top10 = $DB->to_array();
    +	}
    +
    +	$i = 1;
    +	foreach($Top10 as $Torrent) {
    +		list($TorrentID,$GroupID,$GroupName,$GroupCategoryID,$TorrentTags,
    +			$Format,$Encoding,$Media,$Scene,$HasLog,$HasCue,$LogScore,$Year,$GroupYear,
    +			$RemasterTitle,$Snatched,$Seeders,$Leechers,$Data) = $Torrent;
    +
    +		$DisplayName='';
    +		
    +		$Artists = get_artist($GroupID);
    +		
    +		if(!empty($Artists)) {
    +			$DisplayName = display_artists($Artists, false, true);
    +		}
    +		
    +		$DisplayName.= $GroupName;
    +
    +		if($GroupCategoryID==1 && $GroupYear>0) {
    +			$DisplayName.= " [$GroupYear]";
    +		}
    +
    +		// append extra info to torrent title
    +		$ExtraInfo='';
    +		$AddExtra='';
    +		if($Format) { $ExtraInfo.=$Format; $AddExtra=' / '; }
    +		if($Encoding) { $ExtraInfo.=$AddExtra.$Encoding; $AddExtra=' / '; }
    +		// "FLAC / Lossless / Log (100%) / Cue / CD";
    +		if($HasLog) { $ExtraInfo.=$AddExtra."Log (".$LogScore."%)"; $AddExtra=' / '; }
    +		if($HasCue) { $ExtraInfo.=$AddExtra."Cue"; $AddExtra=' / '; }
    +		if($Media) { $ExtraInfo.=$AddExtra.$Media; $AddExtra=' / '; }
    +		if($Scene) { $ExtraInfo.=$AddExtra.'Scene'; $AddExtra=' / '; }
    +		if($Year>0) { $ExtraInfo.=$AddExtra.$Year; $AddExtra=' '; }
    +		if($RemasterTitle) { $ExtraInfo.=$AddExtra.$RemasterTitle; }
    +		if($ExtraInfo!='') {
    +			$ExtraInfo = "- [$ExtraInfo]";
    +		}
    +
    +		$TitleString = $DisplayName.' '.$ExtraInfo;
    +
    +		$TagString = str_replace("|", " ", $TorrentTags);
    +
    +		$DB->query("INSERT INTO top10_history_torrents
    +			(HistoryID, Rank, TorrentID, TitleString, TagString)
    +			VALUES
    +			(".$HistoryID.", ".$i.", ".$TorrentID.", '".db_string($TitleString)."', '".db_string($TagString)."')");
    +		$i++;
    +	}
    +
    +	// Weekly top 10 history.
    +	// We need to haxxor it to work on a Sunday as we don't have a weekly schedule
    +	if(date('w') == 0) {
    +		$DB->query("INSERT INTO top10_history (Date, Type) VALUES ('".$sqltime."', 'Weekly')");
    +		$HistoryID = $DB->inserted_id();
    +
    +		$Top10 = $Cache->get_value('top10tor_week_10');
    +		if($Top10 === false) {
    +			$DB->query("SELECT
    +					t.ID,
    +					g.ID,
    +					g.Name,
    +					g.CategoryID,
    +					g.TagList,
    +					t.Format,
    +					t.Encoding,
    +					t.Media,
    +					t.Scene,
    +					t.HasLog,
    +					t.HasCue,
    +					t.LogScore,
    +					t.RemasterYear,
    +					g.Year,
    +					t.RemasterTitle,
    +					t.Snatched,
    +					t.Seeders,
    +					t.Leechers,
    +					((t.Size * t.Snatched) + (t.Size * 0.5 * t.Leechers)) AS Data
    +				FROM torrents AS t
    +					LEFT JOIN torrents_group AS g ON g.ID = t.GroupID
    +				WHERE t.Seeders>0
    +					AND t.Time > ('".$sqltime."' - INTERVAL 1 WEEK)
    +				ORDER BY (t.Seeders + t.Leechers) DESC
    +					LIMIT 10;");
    +
    +			$Top10 = $DB->to_array();
    +		}
    +
    +		$i = 1;
    +		foreach($Top10 as $Torrent) {
    +			list($TorrentID,$GroupID,$GroupName,$GroupCategoryID,$TorrentTags,
    +				$Format,$Encoding,$Media,$Scene,$HasLog,$HasCue,$LogScore,$Year,$GroupYear,
    +				$RemasterTitle,$Snatched,$Seeders,$Leechers,$Data) = $Torrent;
    +
    +			$DisplayName='';
    +			
    +			$Artists = get_artist($GroupID);
    +			
    +			if(!empty($Artists)) {
    +				$DisplayName = display_artists($Artists, false, true);
    +			}
    +			
    +			$DisplayName.= $GroupName;
    +
    +			if($GroupCategoryID==1 && $GroupYear>0) {
    +				$DisplayName.= " [$GroupYear]";
    +			}
    +
    +			// append extra info to torrent title
    +			$ExtraInfo='';
    +			$AddExtra='';
    +			if($Format) { $ExtraInfo.=$Format; $AddExtra=' / '; }
    +			if($Encoding) { $ExtraInfo.=$AddExtra.$Encoding; $AddExtra=' / '; }
    +			// "FLAC / Lossless / Log (100%) / Cue / CD";
    +			if($HasLog) { $ExtraInfo.=$AddExtra."Log (".$LogScore."%)"; $AddExtra=' / '; }
    +			if($HasCue) { $ExtraInfo.=$AddExtra."Cue"; $AddExtra=' / '; }
    +			if($Media) { $ExtraInfo.=$AddExtra.$Media; $AddExtra=' / '; }
    +			if($Scene) { $ExtraInfo.=$AddExtra.'Scene'; $AddExtra=' / '; }
    +			if($Year>0) { $ExtraInfo.=$AddExtra.$Year; $AddExtra=' '; }
    +			if($RemasterTitle) { $ExtraInfo.=$AddExtra.$RemasterTitle; }
    +			if($ExtraInfo!='') {
    +				$ExtraInfo = "- [$ExtraInfo]";
    +			}
    +
    +			$TitleString = $DisplayName.' '.$ExtraInfo;
    +
    +			$TagString = str_replace("|", " ", $TorrentTags);
    +
    +			$DB->query("INSERT INTO top10_history_torrents
    +				(HistoryID, Rank, TorrentID, TitleString, TagString)
    +				VALUES
    +				(".$HistoryID.", ".$i.", ".$TorrentID.", '".db_string($TitleString)."', '".db_string($TagString)."')");
    +			$i++;
    +		}
    +	
    +		// Send warnings to uploaders of torrents that will be deleted this week
    +		$DB->query("SELECT
    +			t.ID,
    +			t.GroupID,
    +			tg.Name,
    +			t.Format,
    +			t.Encoding,
    +			t.UserID
    +			FROM torrents AS t
    +			JOIN torrents_group AS tg ON tg.ID = t.GroupID
    +			JOIN users_info AS u ON u.UserID = t.UserID
    +			LEFT JOIN artists_group AS ag ON ag.ArtistID = tg.ArtistID
    +			WHERE t.last_action < NOW() - INTERVAL 20 DAY
    +			AND t.last_action != 0
    +			AND u.UnseededAlerts = '1'
    +			ORDER BY t.last_action ASC");
    +		$TorrentIDs = $DB->to_array();
    +		$TorrentAlerts = array();
    +		foreach ($TorrentIDs as $TorrentID) {
    +			list($ID, $GroupID, $Name, $Format, $Encoding, $UserID) = $TorrentID;
    +			
    +			if (array_key_exists($UserID, $InactivityExceptionsMade) && (time() < $InactivityExceptionsMade[$UserID])) {
    +				// don't notify exceptions
    +				continue;	
    +			}
    +			
    +			if (!array_key_exists($UserID, $TorrentAlerts))
    +				$TorrentAlerts[$UserID] = array('Count' => 0, 'Msg' => '');
    +			$ArtistName = display_artists(get_artist($GroupID), false, false, false);
    +			if($ArtistName) {
    +				$Name = $ArtistName.' - '.$Name;
    +			}
    +			if($Format && $Encoding) {
    +				$Name.=' ['.$Format.' / '.$Encoding.']';
    +			}
    +			$TorrentAlerts[$UserID]['Msg'] .= "\n[url=http://".NONSSL_SITE_URL."/torrents.php?torrentid=$ID]".$Name."[/url]";
    +			$TorrentAlerts[$UserID]['Count']++;
    +		}
    +		foreach($TorrentAlerts as $UserID => $MessageInfo){
    +			send_pm($UserID, 0, db_string('Unseeded torrent notification'), db_string($MessageInfo['Count']." of your upload".($MessageInfo['Count']>1?'s':'')." will be deleted for inactivity soon.  Unseeded torrents are deleted after 4 weeks. If you still have the files, you can seed your uploads by ensuring the torrents are in your client and that they aren't stopped. You can view the time that a torrent has been unseeded by clicking on the torrent description line and looking for the \"Last active\" time. For more information, please go [url=http://what.cd/wiki.php?action=article&id=663]here[/url].\n\nThe following torrent".($MessageInfo['Count']>1?'s':'')." will be removed for inactivity:".$MessageInfo['Msg']."\n\nIf you no longer wish to recieve these notifications, please disable them in your profile settings."));
    +		}
    +	}
    +}
    +/*************************************************************************\
    +//--------------Run twice per month -------------------------------------//
    +
    +These functions are twice per month, on the 8th and the 22nd.
    +
    +\*************************************************************************/
    +
    +if($BiWeek != next_biweek() || $_GET['runbiweek']) {
    +	echo "Ran bi-weekly functions\n";
    +
    +	//------------- Cycle auth keys -----------------------------------------//
    +
    +	$DB->query("UPDATE users_info
    +	SET AuthKey =
    +		MD5(
    +			CONCAT(
    +				AuthKey, RAND(), '".db_string(make_secret())."',
    +				SHA1(
    +					CONCAT(
    +						RAND(), RAND(), '".db_string(make_secret())."'
    +					)
    +				)
    +			)
    +		);"
    +	);
    +
    +	//------------- Give out invites! ---------------------------------------//
    +
    +	/*
    +	PUs have a cap of 2 invites.  Elites have a cap of 4.
    +	Every month, on the 8th and the 22nd, each PU/Elite User gets one invite up to their max.
    +
    +	Then, every month, on the 8th and the 22nd, we give out bonus invites like this:
    +
    +	Every Power User or Elite whose total invitee ratio is above 0.75 and total invitee upload is over 2 gigs gets one invite.
    +	Every Elite whose total invitee ratio is above 2.0 and total invitee upload is over 10 gigs gets one more invite.
    +	Every Elite whose total invitee ratio is above 3.0 and total invitee upload is over 20 gigs gets yet one more invite.
    +
    +	This cascades, so if you qualify for the last bonus group, you also qualify for the first two and will receive three bonus invites.
    +
    +	The bonus invites cannot put a user over their cap.
    +	
    +	*/
    +
    +	$DB->query("SELECT ID 
    +				FROM users_main AS um 
    +				JOIN users_info AS ui on ui.UserID=um.ID
    +				WHERE um.Enabled='1' AND ui.DisableInvites = '0'
    +					AND ((um.PermissionID = ".POWER." AND um.Invites < 2) OR (um.PermissionID = ".ELITE." AND um.Invites < 4))");
    +	$UserIDs = $DB->collect('ID');
    +	if (count($UserIDs) > 0) {
    +		foreach($UserIDs as $UserID) {
    +				$Cache->begin_transaction('user_info_heavy_'.$UserID);
    +				$Cache->update_row(false, array('Invites' => '+1'));
    +				$Cache->commit_transaction(0);
    +		}
    +		$DB->query("UPDATE users_main SET Invites=Invites+1 WHERE ID IN (".implode(',',$UserIDs).")");
    +	}
    +
    +	$BonusReqs = array(
    +		array(0.75, 2*1024*1024*1024),
    +		array(2.0, 10*1024*1024*1024),
    +		array(3.0, 20*1024*1024*1024));
    +	
    +	// Since MySQL doesn't like subselecting from the target table during an update, we must create a temporary table.
    +
    +	$DB->query("CREATE TEMPORARY TABLE temp_sections_schedule_index
    +		SELECT SUM(Uploaded) AS Upload,SUM(Downloaded) AS Download,Inviter
    +		FROM users_main AS um JOIN users_info AS ui ON ui.UserID=um.ID
    +		GROUP BY Inviter");
    +	
    +	foreach ($BonusReqs as $BonusReq) {
    +		list($Ratio, $Upload) = $BonusReq;
    +		$DB->query("SELECT ID
    +					FROM users_main AS um 
    +					JOIN users_info AS ui ON ui.UserID=um.ID
    +					JOIN temp_sections_schedule_index AS u ON u.Inviter = um.ID
    +					WHERE u.Upload>$Upload AND u.Upload/u.Download>$Ratio 
    +						AND um.Enabled = '1' AND ui.DisableInvites = '0' 
    +						AND ((um.PermissionID = ".POWER." AND um.Invites < 2) OR (um.PermissionID = ".ELITE." AND um.Invites < 4))");
    +		$UserIDs = $DB->collect('ID');
    +		if (count($UserIDs) > 0) {
    +			foreach($UserIDs as $UserID) {
    +					$Cache->begin_transaction('user_info_heavy_'.$UserID);
    +					$Cache->update_row(false, array('Invites' => '+1'));
    +					$Cache->commit_transaction(0);
    +			}
    +			$DB->query("UPDATE users_main SET Invites=Invites+1 WHERE ID IN (".implode(',',$UserIDs).")");
    +		}
    +	}
    +	
    +	if($BiWeek == 8) {
    +		$DB->query("TRUNCATE TABLE top_snatchers;");
    +		$DB->query("INSERT INTO top_snatchers (UserID) SELECT uid FROM xbt_snatched GROUP BY uid ORDER BY COUNT(uid) DESC LIMIT 100;");
    +	}
    +}
    +
    +
    +echo "-------------------------\n\n";
    +if (check_perms('admin_schedule')) {	
    +	echo '
    ';
    +	show_footer();
    +}
    +?>
    diff --git a/sections/staff/functions.php b/sections/staff/functions.php
    new file mode 100644
    index 00000000..24040e76
    --- /dev/null
    +++ b/sections/staff/functions.php
    @@ -0,0 +1,88 @@
    +get_value('fls')) === false) {
    +		$DB->query("SELECT
    +			m.ID,
    +			p.Level,
    +			m.Username,
    +			m.Paranoia,
    +			m.LastAccess,
    +			i.SupportFor
    +			FROM users_info AS i
    +			JOIN users_main AS m ON m.ID=i.UserID
    +			JOIN permissions AS p ON p.ID=m.PermissionID
    +			WHERE p.DisplayStaff!='1' AND i.SupportFor!=''");
    +		$FLS = $DB->to_array(false, MYSQLI_BOTH, array(3,'Paranoia'));
    +		$Cache->cache_value('fls', $FLS, 180);
    +	}
    +	return $FLS;
    +}
    +
    +function get_forum_staff() {
    +	global $Cache, $DB;
    +	static $ForumStaff;
    +	if(is_array($ForumStaff)) {
    +		return $ForumStaff;
    +	}
    +	if(($ForumStaff = $Cache->get_value('forum_staff')) === false) {
    +		$DB->query("SELECT
    +			m.ID,
    +			p.Level,
    +			m.Username,
    +			m.Paranoia,
    +			m.LastAccess,
    +			i.SupportFor
    +			FROM users_main AS m
    +			JOIN users_info AS i ON m.ID=i.UserID
    +			JOIN permissions AS p ON p.ID=m.PermissionID
    +			WHERE p.DisplayStaff='1'
    +				AND p.Level < 700
    +			ORDER BY p.Level, m.LastAccess ASC");
    +		$ForumStaff = $DB->to_array(false, MYSQLI_BOTH, array(3,'Paranoia'));
    +		$Cache->cache_value('forum_staff', $ForumStaff, 180);
    +	}
    +	return $ForumStaff;
    +}
    +
    +function get_staff() {
    +	global $Cache, $DB;
    +	static $Staff;
    +	if(is_array($Staff)) {
    +		return $Staff;
    +	}
    +	if(($Staff = $Cache->get_value('staff')) === false) {
    +		$DB->query("SELECT
    +			m.ID,
    +			p.Level,
    +			p.Name,
    +			m.Username,
    +			m.Paranoia,
    +			m.LastAccess,
    +			i.SupportFor
    +			FROM users_main AS m
    +			JOIN users_info AS i ON m.ID=i.UserID
    +			JOIN permissions AS p ON p.ID=m.PermissionID
    +			WHERE p.DisplayStaff='1'
    +				AND p.Level >= 700
    +			ORDER BY p.Level, m.LastAccess ASC");
    +		$Staff = $DB->to_array(false, MYSQLI_BOTH, array(4,'Paranoia'));
    +		$Cache->cache_value('staff', $Staff, 180);
    +	}
    +	return $Staff;
    +}
    +
    +function get_support() {
    +	return array(
    +		get_fls(),
    +		get_forum_staff(),
    +		get_staff(),
    +		'fls' => get_fls(),
    +		'forum_staff' => get_forum_staff(),
    +		'staff' => get_staff()
    +	);
    +}
    diff --git a/sections/staff/index.php b/sections/staff/index.php
    new file mode 100644
    index 00000000..44c062f0
    --- /dev/null
    +++ b/sections/staff/index.php
    @@ -0,0 +1,128 @@
    +
    +
    +

    Staff

    +
    +
    +

    Contact Staff

    +
    +

    If you are looking for help with a general question, we appreciate it if you would only message through the staff inbox, where we can all help you.

    +

    You can do that by sending a message to the Staff Inbox.

    +
    + +
    +

    First-line Support

    +

    These users are not official staff members - they're users who have volunteered their time to help people in need. Please treat them with respect and read this before contacting them.

    + + + + + + + + + + + + + +
    UsernameLast seenSupport for
    + + + + + +
    +
    +
    +
    +

    Forum Moderators

    +

    Forum Mods are users who have been promoted to help moderate the forums. They can only help with forum oriented questions

    + + + + + + + + + + + + + +
    UsernameLast seenRemark
    + + + + + +
    +
    +
    +
    +"; + } + $CurClass = $Class; + $CloseTable = true; + echo '

    '.$ClassName.'s

    '; +?> + + + + + + + + + + + + + +
    UsernameLast seenRemark
    + + + + + +
    + +
    +
    + diff --git a/sections/staffblog/index.php b/sections/staffblog/index.php new file mode 100644 index 00000000..102d4a6d --- /dev/null +++ b/sections/staffblog/index.php @@ -0,0 +1,134 @@ +query("UPDATE staff_blog SET Title='".db_string($_POST['title'])."', Body='".db_string($_POST['body'])."' WHERE ID='".db_string($_POST['blogid'])."'"); + $Cache->delete_value('staff_blog'); + $Cache->delete_value('staff_feed_blog'); + } + header('Location: staffblog.php'); + break; + case 'editblog': + if(is_number($_GET['id'])){ + $BlogID = $_GET['id']; + $DB->query("SELECT Title, Body FROM staff_blog WHERE ID=$BlogID"); + list($Title, $Body, $ThreadID) = $DB->next_record(); + } + break; + case 'deleteblog': + if(is_number($_GET['id'])){ + authorize(); + $DB->query("DELETE FROM staff_blog WHERE ID='".db_string($_GET['id'])."'"); + $Cache->delete_value('staff_blog'); + $Cache->delete_value('staff_feed_blog'); + } + header('Location: staffblog.php'); + break; + + case 'takenewblog': + authorize(); + if (empty($_POST['title'])) { + error("Please enter a title."); + } + $Title = db_string($_POST['title']); + $Body = db_string($_POST['body']); + + $DB->query("INSERT INTO staff_blog (UserID, Title, Body, Time) VALUES ('$LoggedUser[ID]', '".db_string($_POST['title'])."', '".db_string($_POST['body'])."', '".sqltime()."')"); + $Cache->delete_value('staff_blog'); + + send_irc("PRIVMSG ".ADMIN_CHAN." :!blog " . $_POST['title']); + + header('Location: staffblog.php'); + break; + } + } + + ?> +
    +
    + + + + +
    +
    +
    + + + + + +

    Title

    + />
    +

    Body

    +
    +

    +
    + +
    +
    +
    +
    +
    + +
    +get_value('staff_blog')) { + $DB->query("SELECT + b.ID, + um.Username, + b.Title, + b.Body, + b.Time + FROM staff_blog AS b LEFT JOIN users_main AS um ON b.UserID=um.ID + ORDER BY Time DESC + LIMIT 20"); + $Blog = $DB->to_array(); + $Cache->cache_value('Blog',$Blog,1209600); +} + +$DB->query("INSERT INTO staff_blog_visits (UserID, Time) VALUES (".$LoggedUser['ID'].", NOW()) ON DUPLICATE KEY UPDATE Time=NOW()"); +$Cache->delete_value('staff_blog_read_'.$LoggedUser['ID']); + +foreach ($Blog as $BlogItem) { + list($BlogID, $Author, $Title, $Body, $BlogTime) = $BlogItem; +?> +
    +
    + - posted by + + - [Edit] + [Delete] + +
    +
    + full_format($Body)?> +
    +
    +
    + +
    + diff --git a/sections/staffpm/ajax_delete_response.php b/sections/staffpm/ajax_delete_response.php new file mode 100644 index 00000000..edf8142a --- /dev/null +++ b/sections/staffpm/ajax_delete_response.php @@ -0,0 +1,29 @@ +query(" + SELECT + i.SupportFor, + p.DisplayStaff + FROM users_info as i + JOIN users_main as m ON m.ID = i.UserID + JOIN permissions as p ON p.ID = m.PermissionID + WHERE i.UserID = ".$LoggedUser['ID'] +); +list($SupportFor, $DisplayStaff) = $DB->next_record(); + +if (!($SupportFor != '' || $DisplayStaff == '1')) { + // Logged in user is not FLS or Staff + error(403); +} + +if ($ID = (int)$_POST['id']) { + $DB->query("DELETE FROM staff_pm_responses WHERE ID=$ID"); + echo '1'; + +} else { + // No id + echo '-1'; +} +?> \ No newline at end of file diff --git a/sections/staffpm/ajax_edit_response.php b/sections/staffpm/ajax_edit_response.php new file mode 100644 index 00000000..c1486d81 --- /dev/null +++ b/sections/staffpm/ajax_edit_response.php @@ -0,0 +1,48 @@ +query(" + SELECT + i.SupportFor, + p.DisplayStaff + FROM users_info as i + JOIN users_main as m ON m.ID = i.UserID + JOIN permissions as p ON p.ID = m.PermissionID + WHERE i.UserID = ".$LoggedUser['ID'] +); +list($SupportFor, $DisplayStaff) = $DB->next_record(); + +if (!($SupportFor != '' || $DisplayStaff == '1')) { + // Logged in user is not FLS or Staff + error(403); +} + +if (($Message = db_string($_POST['message'])) && ($Name = db_string($_POST['name']))) { + $ID = (int)$_POST['id']; + if (is_numeric($ID)) { + if ($ID == 0) { + // Create new response + $DB->query("INSERT INTO staff_pm_responses (Message, Name) VALUES ('$Message', '$Name')"); + echo '1'; + } else { + $DB->query("SELECT * FROM staff_pm_responses WHERE ID=$ID"); + if ($DB->record_count() != 0) { + // Edit response + $DB->query("UPDATE staff_pm_responses SET Message='$Message', Name='$Name' WHERE ID=$ID"); + echo '2'; + } else { + // Create new response + $DB->query("INSERT INTO staff_pm_responses (Message, Name) VALUES ('$Message', '$Name')"); + echo '1'; + } + } + } else { + // No id + echo '-2'; + } + +} else { + // No message/name + echo '-1'; +} +?> \ No newline at end of file diff --git a/sections/staffpm/ajax_get_response.php b/sections/staffpm/ajax_get_response.php new file mode 100644 index 00000000..ffdef5c7 --- /dev/null +++ b/sections/staffpm/ajax_get_response.php @@ -0,0 +1,36 @@ +query(" + SELECT + i.SupportFor, + p.DisplayStaff + FROM users_info as i + JOIN users_main as m ON m.ID = i.UserID + JOIN permissions as p ON p.ID = m.PermissionID + WHERE i.UserID = ".$LoggedUser['ID'] +); +list($SupportFor, $DisplayStaff) = $DB->next_record(); + +if (!($SupportFor != '' || $DisplayStaff == '1')) { + // Logged in user is not FLS or Staff + error(403); +} + +if ($ID = (int)$_GET['id']) { + $DB->query("SELECT Message FROM staff_pm_responses WHERE ID=$ID"); + list($Message) = $DB->next_record(); + if ($_GET['plain'] == 1) { + echo $Message; + } else { + include(SERVER_ROOT.'/classes/class_text.php'); // Text formatting class + $Text = new TEXT; + echo $Text->full_format($Message); + } + +} else { + // No id + echo '-1'; +} +?> diff --git a/sections/staffpm/ajax_preview_response.php b/sections/staffpm/ajax_preview_response.php new file mode 100644 index 00000000..8df66436 --- /dev/null +++ b/sections/staffpm/ajax_preview_response.php @@ -0,0 +1,10 @@ +full_format($_POST['message']); +} +?> diff --git a/sections/staffpm/assign.php b/sections/staffpm/assign.php new file mode 100644 index 00000000..c3322e42 --- /dev/null +++ b/sections/staffpm/assign.php @@ -0,0 +1,72 @@ +query("SELECT Level FROM staff_pm_conversations WHERE ID=$ConvID"); + list($Level) = $DB->next_record; + + if ($Level == 0) { + // FLS conversation, assign to staff (moderator) + if(!empty($_GET['to'])) { + $Level = 0; + switch($_GET['to']) { + case 'forum' : + $Level = 650; + break; + case 'staff' : + $Level = 700; + break; + default : + error(404); + break; + } + + $DB->query("UPDATE staff_pm_conversations SET Status='Unanswered', Level=".$Level." WHERE ID=$ConvID"); + header('Location: staffpm.php'); + } else { + error(404); + } + } else { + // FLS trying to assign non-FLS conversation + error(403); + } + +} elseif ($ConvID = (int)$_POST['convid']) { + // Staff (via ajax), get current assign of conversation + $DB->query("SELECT Level, AssignedToUser FROM staff_pm_conversations WHERE ID=$ConvID"); + list($Level, $AssignedToUser) = $DB->next_record; + + if ($LoggedUser['Class'] >= $Level || $AssignedToUser == $LoggedUser['ID']) { + // Staff member is allowed to assign conversation, assign + list($LevelType, $NewLevel) = explode("_", db_string($_POST['assign'])); + + if ($LevelType == 'class') { + // Assign to class + $DB->query("UPDATE staff_pm_conversations SET Status='Unanswered', Level=$NewLevel, AssignedToUser=NULL WHERE ID=$ConvID"); + } else { + $UserInfo = user_info($NewLevel); + $Level = $Classes[$UserInfo['PermissionID']]['Level']; + if (!$Level) { + error("Assign to user not found."); + } + + // Assign to user + $DB->query("UPDATE staff_pm_conversations SET Status='Unanswered', AssignedToUser=$NewLevel, Level=$Level WHERE ID=$ConvID"); + + } + echo '1'; + + } else { + // Staff member is not allowed to assign conversation + echo '-1'; + } + +} else { + // No id + header('Location: staffpm.php'); +} +?> diff --git a/sections/staffpm/common_responses.php b/sections/staffpm/common_responses.php new file mode 100644 index 00000000..3ce6bf31 --- /dev/null +++ b/sections/staffpm/common_responses.php @@ -0,0 +1,99 @@ + +
    +

    Staff PMs - Manage common responses

    + +
    +
    + +
    +
    +

    Create new response:

    +
    +
    +
    +
    + Name: + +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +

    Edit old responses:

    +
    +query("SELECT ID, Message, Name FROM staff_pm_responses ORDER BY ID DESC"); +while(list($ID, $Message, $Name) = $DB->next_record()) { + +?> +
    + +
    +
    +
    +
    + Name: + + +
    +
    + + +
    + + + +
    +
    +
    + +
    +
    + diff --git a/sections/staffpm/functions.php b/sections/staffpm/functions.php new file mode 100644 index 00000000..f233d6c7 --- /dev/null +++ b/sections/staffpm/functions.php @@ -0,0 +1,25 @@ + +
    +
    + + + +
    + + + +
    + + Send to: + + + + +
    +
    + diff --git a/sections/staffpm/index.php b/sections/staffpm/index.php new file mode 100644 index 00000000..fdd3749d --- /dev/null +++ b/sections/staffpm/index.php @@ -0,0 +1,69 @@ +query(" + SELECT + i.SupportFor, + p.DisplayStaff + FROM users_info as i + JOIN users_main as m ON m.ID = i.UserID + JOIN permissions as p ON p.ID = m.PermissionID + WHERE i.UserID = ".$LoggedUser['ID'] +); +list($SupportFor, $DisplayStaff) = $DB->next_record(); +// Logged in user is staff +$IsStaff = ($DisplayStaff == 1); +// Logged in user is Staff or FLS +$IsFLS = ($SupportFor != '' || $IsStaff); + +switch($_REQUEST['action']) { + case 'viewconv': + require('viewconv.php'); + break; + case 'takepost': + require('takepost.php'); + break; + case 'resolve': + require('resolve.php'); + break; + case 'unresolve': + require('unresolve.php'); + break; + case 'multiresolve': + require('multiresolve.php'); + break; + case 'assign': + require('assign.php'); + break; + case 'make_donor': + require('makedonor.php'); + break; + case 'responses': + require('common_responses.php'); + break; + case 'get_response': + require('ajax_get_response.php'); + break; + case 'delete_response': + require('ajax_delete_response.php'); + break; + case 'edit_response': + require('ajax_edit_response.php'); + break; + case 'preview': + require('ajax_preview_response.php'); + break; + default: + if ($IsStaff || $IsFLS) { + require('staff_inbox.php'); + } else { + require('user_inbox.php'); + } + break; +} + +?> diff --git a/sections/staffpm/makedonor.php b/sections/staffpm/makedonor.php new file mode 100644 index 00000000..8d8b3001 --- /dev/null +++ b/sections/staffpm/makedonor.php @@ -0,0 +1,43 @@ +query("SELECT c.Subject, c.UserID, c.Level, c.AssignedToUser, c.Unread, c.Status, u.Donor + FROM staff_pm_conversations AS c + JOIN users_info AS u ON u.UserID = c.UserID + WHERE ID=$ConvID"); + list($Subject, $UserID, $Level, $AssignedToUser, $Unread, $Status, $Donor) = $DB->next_record(); + if ($DB->record_count() == 0) { + error(404); + } + + $Message = "Thank for for helping to support the site. It's users like you who make all of this possible."; + + if ((int)$Donor === 0) { + $Msg = db_string(sqltime() . ' - Donated: http://'.NONSSL_SITE_URL."/staffpm.php?action=viewconv&id=$ConvID\n\n"); + $DB->query("UPDATE users_info + SET Donor='1', + AdminComment = CONCAT('$Msg',AdminComment) + WHERE UserID = $UserID"); + $DB->query("UPDATE users_main SET Invites=Invites+2 WHERE ID = $UserID"); + + $Cache->delete_value('user_info_'.$UserID); + $Cache->delete_value('user_info_heavy_'.$UserID); + $Message .= " Enjoy your new love from us!"; + } else { + $Message .= " "; + } + $DB->query("INSERT INTO staff_pm_messages (UserID, SentDate, Message, ConvID) + VALUES (".$LoggedUser['ID'].", '".sqltime()."', '".db_string($Message)."', $ConvID)"); + $DB->query("UPDATE staff_pm_conversations + SET Date='".sqltime()."', Unread=true, + Status='Resolved', ResolverID=".$LoggedUser['ID']." + WHERE ID=$ConvID"); + header('Location: staffpm.php'); +?> \ No newline at end of file diff --git a/sections/staffpm/multiresolve.php b/sections/staffpm/multiresolve.php new file mode 100644 index 00000000..829e3b3a --- /dev/null +++ b/sections/staffpm/multiresolve.php @@ -0,0 +1 @@ +query("SELECT UserID, AssignedToUser FROM staff_pm_conversations WHERE ID=$ID"); list($UserID, $AssignedToUser) = $DB->next_record(); if ($UserID == $LoggedUser['ID'] || $DisplayStaff == '1' || $UserID == $AssignedToUser) { // Conversation belongs to user or user is staff, queue query $Queries[] = "UPDATE staff_pm_conversations SET Status='Resolved', ResolverID=".$LoggedUser['ID']." WHERE ID=$ID"; } else { // Trying to run disallowed query error(403); } } // Run queries foreach ($Queries as $Query) { $DB->query($Query); } // Clear cache for user $Cache->delete_value('staff_pm_new_'.$LoggedUser['ID']); $Cache->delete_value('num_staff_pms_'.$LoggedUser['ID']); // Done! Return to inbox header("Location: staffpm.php"); } else { // No id header("Location: staffpm.php"); } ?> \ No newline at end of file diff --git a/sections/staffpm/resolve.php b/sections/staffpm/resolve.php new file mode 100644 index 00000000..8394678a --- /dev/null +++ b/sections/staffpm/resolve.php @@ -0,0 +1,22 @@ +query("SELECT UserID, AssignedToUser FROM staff_pm_conversations WHERE ID=$ID"); + list($UserID, $AssignedToUser) = $DB->next_record(); + + if ($UserID == $LoggedUser['ID'] || $IsFLS || $AssignedToUser == $LoggedUser['ID']) { + // Conversation belongs to user or user is staff, resolve it + $DB->query("UPDATE staff_pm_conversations SET Status='Resolved', ResolverID=".$LoggedUser['ID']." WHERE ID=$ID"); + $Cache->delete_value('staff_pm_new_'.$LoggedUser['ID']); + $Cache->delete_value('num_staff_pms_'.$LoggedUser['ID']); + + header('Location: staffpm.php'); + } else { + // Conversation does not belong to user + error(403); + } +} else { + // No id + header('Location: staffpm.php'); +} +?> diff --git a/sections/staffpm/staff_inbox.php b/sections/staffpm/staff_inbox.php new file mode 100644 index 00000000..ab932adc --- /dev/null +++ b/sections/staffpm/staff_inbox.php @@ -0,0 +1,199 @@ += 700) { + $ViewString = "My unanswered"; + $WhereCondition = "WHERE ((Level >= ".max($Classes[MOD]['Level'],700)." AND Level <= $UserLevel) OR AssignedToUser='".$LoggedUser['ID']."') AND Status='Unanswered'"; + } elseif ($UserLevel == 650) { + // Forum Mods + $ViewString = "My Unanswered"; + $WhereCondition = "WHERE (Level = $UserLevel OR AssignedToUser='".$LoggedUser['ID']."') AND Status='Unanswered'"; + } else { + // FLS + $ViewString = "Unanswered"; + $WhereCondition = "WHERE (Level <= $UserLevel OR AssignedToUser='".$LoggedUser['ID']."') AND Status='Unanswered'"; + } + break; +} + +list($Page,$Limit) = page_limit(MESSAGES_PER_PAGE); +// Get messages +$StaffPMs = $DB->query(" + SELECT + SQL_CALC_FOUND_ROWS + ID, + Subject, + UserID, + Status, + Level, + AssignedToUser, + Date, + Unread, + ResolverID + FROM staff_pm_conversations + $WhereCondition + ORDER BY $SortStr Level DESC, Date DESC + LIMIT $Limit +"); + +$DB->query('SELECT FOUND_ROWS()'); +list($NumResults) = $DB->next_record(); +$DB->set_query_id($StaffPMs); + +$CurURL = get_url(); +if(empty($CurURL)) { + $CurURL = "staffpm.php?"; +} else { + $CurURL = "staffpm.php?".$CurURL."&"; +} +$Pages=get_pages($Page,$NumResults,MESSAGES_PER_PAGE,9); + +$Row = 'a'; + +// Start page +?> +
    +

    Staff PMs

    + +
    +record_count() == 0) { + // No messages +?> +

    No messages

    + +
    + + + + + + + + + + + + + + + + +next_record()) { + $Row = ($Row === 'a') ? 'b' : 'a'; + $RowClass = 'row'.$Row; + + $UserInfo = user_info($UserID); + $UserStr = format_username($UserID, $UserInfo['Username'], $UserInfo['Donor'], $UserInfo['Warned'], $UserInfo['Enabled'], $UserInfo['PermissionID']); + + // Get assigned + if ($AssignedToUser == '') { + // Assigned to class + $Assigned = ($Level == 0) ? "First Line Support" : $ClassLevels[$Level]['Name']; + // No + on Sysops + if ($Assigned != 'Sysop') { $Assigned .= "+"; } + + } else { + // Assigned to user + $UserInfo = user_info($AssignedToUser); + $Assigned = format_username($AssignedToUser, $UserInfo['Username'], $UserInfo['Donor'], $UserInfo['Warned'], $UserInfo['Enabled'], $UserInfo['PermissionID']); + + } + + // Get resolver + if ($ViewString == 'Resolved') { + $UserInfo = user_info($ResolverID); + $ResolverStr = format_username($ResolverID, $UserInfo['Username'], $UserInfo['Donor'], $UserInfo['Warned'], $UserInfo['Enabled'], $UserInfo['PermissionID']); + } + + // Table row +?> + + + + + + + + + + + + +set_query_id($StaffPMs); + } + + // Close table and multiresolve form +?> +
    SubjectSenderDateAssigned toResolved by
    + + + +
    + +
    + +
    + diff --git a/sections/staffpm/takepost.php b/sections/staffpm/takepost.php new file mode 100644 index 00000000..91d0fbd2 --- /dev/null +++ b/sections/staffpm/takepost.php @@ -0,0 +1,73 @@ +query(" + INSERT INTO staff_pm_conversations + (Subject, Status, Level, UserID, Date) + VALUES + ('$Subject', 'Unanswered', $Level, ".$LoggedUser['ID'].", '".sqltime()."')" + ); + + // New message + $ConvID = $DB->inserted_id(); + $DB->query(" + INSERT INTO staff_pm_messages + (UserID, SentDate, Message, ConvID) + VALUES + (".$LoggedUser['ID'].", '".sqltime()."', '$Message', $ConvID)" + ); + + header('Location: staffpm.php'); + + } elseif ($ConvID = (int)$_POST['convid']) { + // Check if conversation belongs to user + $DB->query("SELECT UserID, AssignedToUser FROM staff_pm_conversations WHERE ID=$ConvID"); + list($UserID, $AssignedToUser) = $DB->next_record(); + + if ($UserID == $LoggedUser['ID'] || $IsFLS || $UserID == $AssignedToUser) { + // Response to existing conversation + $DB->query(" + INSERT INTO staff_pm_messages + (UserID, SentDate, Message, ConvID) + VALUES + (".$LoggedUser['ID'].", '".sqltime()."', '$Message', $ConvID)" + ); + + // Update conversation + if ($IsFLS) { + // FLS/Staff + $DB->query("UPDATE staff_pm_conversations SET Date='".sqltime()."', Unread=true, Status='Open' WHERE ID=$ConvID"); + $Cache->delete_value('num_staff_pms_'.$LoggedUser['ID']); + } else { + // User + $DB->query("UPDATE staff_pm_conversations SET Date='".sqltime()."', Unread=true, Status='Unanswered' WHERE ID=$ConvID"); + } + + // Clear cache for user + $Cache->delete_value('staff_pm_new_'.$UserID); + $Cache->delete_value('staff_pm_new_'.$LoggedUser['ID']); + + header("Location: staffpm.php?action=viewconv&id=$ConvID"); + } else { + // User is trying to respond to conversation that does no belong to them + error(403); + } + + } else { + // Message but no subject or conversation id + header("Location: staffpm.php?action=viewconv&id=$ConvID"); + + } +} elseif ($ConvID = (int)$_POST['convid']) { + // No message, but conversation id + header("Location: staffpm.php?action=viewconv&id=$ConvID"); + +} else { + // No message or conversation id + header('Location: staffpm.php'); +} + + +?> diff --git a/sections/staffpm/unresolve.php b/sections/staffpm/unresolve.php new file mode 100644 index 00000000..040e6e6b --- /dev/null +++ b/sections/staffpm/unresolve.php @@ -0,0 +1,27 @@ +query("SELECT UserID, Level, AssignedToUser FROM staff_pm_conversations WHERE ID=$ID"); + list($UserID, $Level, $AssignedToUser) = $DB->next_record(); + + if ($UserID == $LoggedUser['ID'] || ($IsFLS && $Level == 0) || + $AssignedToUser == $LoggedUser['ID'] || ($IsStaff && $Level <= $LoggedUser['Class'])) { + /*if($Level != 0 && $IsStaff == false) { + error(403); + }*/ + + // Conversation belongs to user or user is staff, unresolve it + $DB->query("UPDATE staff_pm_conversations SET Status='Unanswered' WHERE ID=$ID"); + // Clear cache for user + $Cache->delete_value('num_staff_pms_'.$LoggedUser['ID']); + + header('Location: staffpm.php'); + } else { + // Conversation does not belong to user + error(403); + } +} else { + // No id + header('Location: staffpm.php'); +} +?> diff --git a/sections/staffpm/user_inbox.php b/sections/staffpm/user_inbox.php new file mode 100644 index 00000000..56fa4edb --- /dev/null +++ b/sections/staffpm/user_inbox.php @@ -0,0 +1,118 @@ +query(" + SELECT + ID, + Subject, + UserID, + Status, + Level, + AssignedToUser, + Date, + Unread + FROM staff_pm_conversations + WHERE UserID=".$LoggedUser['ID']." + ORDER BY Status, Date DESC" +); + +// Start page +?> +
    +

    Staff PMs

    + + +
    +record_count() == 0) { + // No messages +?> +

    No messages

    + +
    + +

    Open messages

    + + + + + + + +next_record()) { + if($Unread === '1') { + $RowClass = 'unreadpm'; + } else { + $Row = ($Row === 'a') ? 'b' : 'a'; + $RowClass = 'row'.$Row; + } + + if ($Status == 'Resolved') { $ShowBox++; } + if ($ShowBox == 2) { + // First resolved PM +?> +
    SubjectDateAssigned to
    +
    +

    Resolved messages

    + + + + + + + + + + + + + + + +set_query_id($StaffPMs); + } + + // Close table and multiresolve form +?> +
    SubjectDateAssigned to
    + +
    + +
    +
    + diff --git a/sections/staffpm/viewconv.php b/sections/staffpm/viewconv.php new file mode 100644 index 00000000..0baa9355 --- /dev/null +++ b/sections/staffpm/viewconv.php @@ -0,0 +1,227 @@ +query("SELECT Subject, UserID, Level, AssignedToUser, Unread, Status FROM staff_pm_conversations WHERE ID=$ConvID"); + list($Subject, $UserID, $Level, $AssignedToUser, $Unread, $Status) = $DB->next_record(); + $DB->query("SELECT Subject, UserID, Level, AssignedToUser, Unread, Status FROM staff_pm_conversations WHERE ID=$ConvID"); + list($Subject, $UserID, $Level, $AssignedToUser, $Unread, $Status) = $DB->next_record(); + + if (!(($UserID == $LoggedUser['ID']) || ($AssignedToUser == $LoggedUser['ID']) || (($Level > 0 && $Level <= $LoggedUser['Class']) || ($Level == 0 && $IsFLS)))) { + // User is trying to view someone else's conversation + error(403); + } + // User is trying to view their own unread conversation, set it to read + if ($UserID == $LoggedUser['ID'] && $Unread) { + $DB->query("UPDATE staff_pm_conversations SET Unread=false WHERE ID=$ConvID"); + // Clear cache for user + $Cache->delete_value('staff_pm_new_'.$LoggedUser['ID']); + } + + show_header('Staff PM', 'staffpm,bbcode'); + + $UserInfo = user_info($UserID); + $UserStr = format_username($UserID, $UserInfo['Username'], $UserInfo['Donor'], $UserInfo['Warned'], $UserInfo['Enabled'], $UserInfo['PermissionID']); + + $OwnerID = $UserID; + +?> +
    +

    Staff PM -

    + +
    +query("SELECT UserID, SentDate, Message FROM staff_pm_messages WHERE ConvID=$ConvID"); + + while(list($UserID, $SentDate, $Message) = $DB->next_record()) { + // Set user string + if ($UserID == $OwnerID) { + // User, use prepared string + $UserString = $UserStr; + } else { + // Staff/FLS + $UserInfo = user_info($UserID); + $UserString = format_username($UserID, $UserInfo['Username'], $UserInfo['Donor'], $UserInfo['Warned'], $UserInfo['Enabled'], $UserInfo['PermissionID']); + + } +?> +
    +
    + + + + + + +
    +
    full_format($Message)?>
    +
    +
    +set_query_id($StaffPMs); + } + + // Common responses + if ($IsFLS && $Status != 'Resolved') { +?> + + + + +

    Reply

    +
    + +
    +
    + + +
    + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    +
    + diff --git a/sections/stats/torrents.php b/sections/stats/torrents.php new file mode 100644 index 00000000..a6c35ed9 --- /dev/null +++ b/sections/stats/torrents.php @@ -0,0 +1,70 @@ +get_value('torrents_timeline')) { + $DB->query("SELECT DATE_FORMAT(Time,'%b \'%y') AS Month, COUNT(ID) FROM log WHERE Message LIKE 'Torrent % was uploaded by %' GROUP BY Month ORDER BY Time DESC LIMIT 1, 12"); + $TimelineIn = array_reverse($DB->to_array()); + $DB->query("SELECT DATE_FORMAT(Time,'%b \'%y') AS Month, COUNT(ID) FROM log WHERE Message LIKE 'Torrent % was deleted %' GROUP BY Month ORDER BY Time DESC LIMIT 1, 12"); + $TimelineOut = array_reverse($DB->to_array()); + $DB->query("SELECT DATE_FORMAT(Time,'%b \'%y') AS Month, COUNT(ID) FROM torrents GROUP BY Month ORDER BY Time DESC LIMIT 1, 12"); + $TimelineNet = array_reverse($DB->to_array()); + + foreach($TimelineIn as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + foreach($TimelineOut as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + foreach($TimelineNet as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + foreach($TimelineIn as $Month) { + list($Label,$Amount) = $Month; + $Labels[] = $Label; + $InFlow[] = number_format(($Amount/$Max)*100,4); + } + foreach($TimelineOut as $Month) { + list($Label,$Amount) = $Month; + $OutFlow[] = number_format(($Amount/$Max)*100,4); + } + foreach($TimelineNet as $Month) { + list($Label,$Amount) = $Month; + $NetFlow[] = number_format(($Amount/$Max)*100,4); + } + $Cache->cache_value('torrents_timeline',array($Labels,$InFlow,$OutFlow,$NetFlow,$Max),mktime(0,0,0,date('n')+1,2)); //Tested: fine for dec -> jan +} + +include_once(SERVER_ROOT.'/classes/class_charts.php'); +$DB->query("SELECT tg.CategoryID, COUNT(t.ID) AS Torrents FROM torrents AS t JOIN torrents_group AS tg ON tg.ID=t.GroupID GROUP BY tg.CategoryID ORDER BY Torrents DESC"); +$Groups = $DB->to_array(); +$Pie = new PIE_CHART(750,400,array('Other'=>1,'Percentage'=>1)); +foreach($Groups as $Group) { + list($CategoryID, $Torrents) = $Group; + $CategoryName = $Categories[$CategoryID - 1]; + $Pie->add($CategoryName,$Torrents); +} +$Pie->transparent(); +$Pie->color('FF33CC'); +$Pie->generate(); +$Categories = $Pie->url(); + +show_header(); +?> + +
    +

    Uploads by month

    + +
    +
    +

    Torrents by category

    + +
    +get_value('geodistribution')) { + include_once(SERVER_ROOT.'/classes/class_charts.php'); + $DB->query('SELECT Code, Users FROM users_geodistribution'); + $Data = $DB->to_array(); + $Count = $DB->record_count()-1; + + if($Count<30) { + $CountryMinThreshold = $Count; + } else { + $CountryMinThreshold = 30; + } + + $CountryMax = ceil(log(Max(1,$Data[0][1]))/log(2))+1; + $CountryMin = floor(log(Max(1,$Data[$CountryMinThreshold][1]))/log(2)); + + $CountryRegions = array('RS' => array('RS-KM')); // Count Kosovo as Serbia as it doesn't have a TLD + foreach ($Data as $Key => $Item) { + list($Country,$UserCount) = $Item; + $Countries[] = $Country; + $CountryUsers[] = number_format((((log($UserCount)/log(2))-$CountryMin)/($CountryMax-$CountryMin))*100,2); + $Rank[] = round((1-($Key/$Count))*100); + + if(isset($CountryRegions[$Country])) { + foreach($CountryRegions[$Country] as $Region) { + $Countries[] = $Region; + $Rank[] = end($Rank); + } + } + } + reset($Rank); + + for ($i=$CountryMin;$i<=$CountryMax;$i++) { + $LogIncrements[] = human_format(pow(2,$i)); + } + $Cache->cache_value('geodistribution',array($Countries,$Rank,$CountryUsers,$CountryMax,$CountryMin,$LogIncrements),0); +} + +if(!$ClassDistribution = $Cache->get_value('class_distribution')) { + include_once(SERVER_ROOT.'/classes/class_charts.php'); + $DB->query("SELECT p.Name, COUNT(m.ID) AS Users FROM users_main AS m JOIN permissions AS p ON m.PermissionID=p.ID WHERE m.Enabled='1' GROUP BY p.Name ORDER BY Users DESC"); + $ClassSizes = $DB->to_array(); + $Pie = new PIE_CHART(750,400,array('Other'=>1,'Percentage'=>1)); + foreach($ClassSizes as $ClassSize) { + list($Label,$Users) = $ClassSize; + $Pie->add($Label,$Users); + } + $Pie->transparent(); + $Pie->color('FF33CC'); + $Pie->generate(); + $ClassDistribution = $Pie->url(); + $Cache->cache_value('class_distribution',$ClassDistribution,3600*24*14); +} +if(!$PlatformDistribution = $Cache->get_value('platform_distribution')) { + include_once(SERVER_ROOT.'/classes/class_charts.php'); + + + $DB->query("SELECT OperatingSystem, COUNT(UserID) AS Users FROM users_sessions GROUP BY OperatingSystem ORDER BY Users DESC"); + + $Platforms = $DB->to_array(); + $Pie = new PIE_CHART(750,400,array('Other'=>1,'Percentage'=>1)); + foreach($Platforms as $Platform) { + list($Label,$Users) = $Platform; + $Pie->add($Label,$Users); + } + $Pie->transparent(); + $Pie->color('8A00B8'); + $Pie->generate(); + $PlatformDistribution = $Pie->url(); + $Cache->cache_value('platform_distribution',$PlatformDistribution,3600*24*14); +} + +if(!$BrowserDistribution = $Cache->get_value('browser_distribution')) { + include_once(SERVER_ROOT.'/classes/class_charts.php'); + + + $DB->query("SELECT Browser, COUNT(UserID) AS Users FROM users_sessions GROUP BY Browser ORDER BY Users DESC"); + + $Browsers = $DB->to_array(); + $Pie = new PIE_CHART(750,400,array('Other'=>1,'Percentage'=>1)); + foreach($Browsers as $Browser) { + list($Label,$Users) = $Browser; + $Pie->add($Label,$Users); + } + $Pie->transparent(); + $Pie->color('008AB8'); + $Pie->generate(); + $BrowserDistribution = $Pie->url(); + $Cache->cache_value('browser_distribution',$BrowserDistribution,3600*24*14); +} + + +//Timeline generation +if (!list($Labels,$InFlow,$OutFlow,$Max) = $Cache->get_value('users_timeline')) { + $DB->query("SELECT DATE_FORMAT(JoinDate,'%b \\'%y') AS Month, COUNT(UserID) FROM users_info GROUP BY Month ORDER BY JoinDate DESC LIMIT 1, 12"); + $TimelineIn = array_reverse($DB->to_array()); + $DB->query("SELECT DATE_FORMAT(BanDate,'%b \\'%y') AS Month, COUNT(UserID) FROM users_info GROUP BY Month ORDER BY BanDate DESC LIMIT 1, 12"); + $TimelineOut = array_reverse($DB->to_array()); + foreach($TimelineIn as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + foreach($TimelineOut as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + + $Labels = array(); + foreach($TimelineIn as $Month) { + list($Label,$Amount) = $Month; + $Labels[] = $Label; + $InFlow[] = number_format(($Amount/$Max)*100,4); + } + foreach($TimelineOut as $Month) { + list($Label,$Amount) = $Month; + $OutFlow[] = number_format(($Amount/$Max)*100,4); + } + $Cache->cache_value('users_timeline',array($Labels,$InFlow,$OutFlow,$Max),mktime(0,0,0,date('n')+1,2)); //Tested: fine for dec -> jan +} +//End timeline generation + +show_header('Detailed User Statistics'); +?> +

    User Flow

    +
    + +
    +
    +

    User Classes

    +
    + +
    +
    +

    User Platforms

    +
    + +
    +
    +

    User Browsers

    +
    + +
    +
    +

    Geographical Distribution Map

    +
    + + +
    + + +
    + + +
    + +
    +query("SELECT m.ID, m.Username, i.Donor, i.BitcoinAddress FROM users_main m INNER JOIN users_info i ON m.ID = i.UserID WHERE BitcoinAddress IS NOT NULL"); +?> +
    +

    + + + + + + +next_record()) { + $amount = false; + foreach ($Receiveds as $R) { + if ($R->address == $row['BitcoinAddress']) { + $amount = $R->amount . ' BTC'; + } + } + if ($amount === false) { continue; } + ?> + + + + + + +
    UsernameReceiving bitcoin addressAmount
    +
    + diff --git a/sections/tools/data/browser_support.php b/sections/tools/data/browser_support.php new file mode 100644 index 00000000..9cdc3b7e --- /dev/null +++ b/sections/tools/data/browser_support.php @@ -0,0 +1,20 @@ +get_value('support_'.$Campaign)) { $Votes = array(0,0); } +if (!isset($_GET['support'])) { +?> +

    Browser Support Campaign:

    +
      +
    • +
    • +
    • -
    • +
    • %
    • +
    +cache_value('support_'.$Campaign,$Votes,0); + +?> diff --git a/sections/tools/data/database_specifics.php b/sections/tools/data/database_specifics.php new file mode 100644 index 00000000..1a054049 --- /dev/null +++ b/sections/tools/data/database_specifics.php @@ -0,0 +1,140 @@ +query('SHOW TABLES'); + $Tables =$DB->collect('Tables_in_'.SQLDB); + if (!in_array($_GET['table'], $Tables)) { + error(0); + } + $DB->query('SHOW CREATE TABLE '.db_string($_GET['table'])); + list(,$Schema) = $DB->next_record(MYSQLI_NUM, false); + header('Content-type: text/plain'); + die($Schema); +} + +//Cache the tables for 4 hours, makes sorting faster +if (!$Tables = $Cache->get_value('database_table_stats')) { + $DB->query('SHOW TABLE STATUS'); + $Tables =$DB->to_array(); + $Cache->cache_value('database_table_stats',$Tables,3600*4); +} + +require(SERVER_ROOT.'/classes/class_charts.php'); +$Pie = new PIE_CHART(750,400,array('Other'=>1,'Percentage'=>1,'Sort'=>1)); + +//Begin sorting +$Sort = array(); +switch (empty($_GET['order_by'])?'':$_GET['order_by']) { + case 'name': + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[6] + $Value[8]); + $Sort[$Key] = $Value[0]; + } + break; + case 'engine': + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[6] + $Value[8]); + $Sort[$Key] = $Value[1]; + } + break; + case 'rows': + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[4]); + $Sort[$Key] = $Value[4]; + } + break; + case 'rowsize': + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[5]); + $Sort[$Key] = $Value[5]; + } + break; + case 'datasize': + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[6]); + $Sort[$Key] = $Value[6]; + } + break; + case 'indexsize': + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[8]); + $Sort[$Key] = $Value[8]; + } + break; + case 'totalsize': + default: + foreach ($Tables as $Key => $Value) { + $Pie->add($Value[0], $Value[6] + $Value[8]); + $Sort[$Key] = $Value[6] + $Value[8]; + } +} +$Pie->generate(); + +if (!empty ($_GET['order_way']) && $_GET['order_way'] == 'asc') { + $SortWay = SORT_ASC; +} else { + $SortWay = SORT_DESC; +} + +array_multisort($Sort, $SortWay, $Tables); +//End sorting + +show_header('Database Specifics'); +?> +

    Breakdown

    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameEngineRowsRow SizeData SizeIndex SizeTotal SizeTools
    [Schema]
    +query($sql); +$Donations = $DB->to_array(false,MYSQLI_NUM); + +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); + +if (empty($_GET['search']) && !isset($_GET['page']) && !$DonationTimeline = $Cache->get_value('donation_timeline')) { + include(SERVER_ROOT.'/classes/class_charts.php'); + $DB->query("SELECT DATE_FORMAT(Time,'%b \'%y') AS Month, SUM(Amount) FROM donations GROUP BY Month ORDER BY Time DESC LIMIT 1, 18"); + $Timeline = array_reverse($DB->to_array()); + $Area = new AREA_GRAPH(880,160,array('Break'=>1)); + foreach($Timeline as $Entry) { + list($Label,$Amount) = $Entry; + $Area->add($Label,$Amount); + } + $Area->transparent(); + $Area->grid_lines(); + $Area->color('3d7930'); + $Area->lines(2); + $Area->generate(); + $DonationTimeline = $Area->url(); + $Cache->cache_value('donation_timeline',$DonationTimeline,mktime(0,0,0,date('n')+1,2)); +} + +show_header('Donation log'); +if (empty($_GET['search']) && !isset($_GET['page'])) { +?> +
    + +
    +
    + +
    +
    + + + + + +
    Email: + + +   + +
    +
    +
    +
    + + + + + + + + + + + + + + + + +
    UserAmountEmailTime
    + + diff --git a/sections/tools/data/economic_stats.php b/sections/tools/data/economic_stats.php new file mode 100644 index 00000000..eb41579a --- /dev/null +++ b/sections/tools/data/economic_stats.php @@ -0,0 +1,120 @@ +50% of accounts with ratios >1 reach 1.0 and never dip below, stockpiling buffer +5. Raw numbers + a. total torrents, seeders, leechers + b. average seeds/leechs per torrent + c. average snatches/user + d. average seeding torrents/user + e. users on ratio watch +6. Distribution graph of seedership vs. torrent percentage + a. graph showing that the top 1% of torrents has 50% of seeders or whatever the numbers might be +7. Effects of economic changes + a. number of users changed by ratio being changed + b. project effects with intelligent mathematical analysis of a 24, 48 or 72 hour freeleech +*/ +if(!check_perms('site_view_flow')) { error(403); } +show_header('Economy'); + +if (!$EconomicStats = $Cache->get_value('new_economic_stats')) { + $DB->query("SELECT SUM(Uploaded), SUM(Downloaded), COUNT(ID) FROM users_main WHERE Enabled='1'"); + list($TotalUpload, $TotalDownload, $NumUsers) = $DB->next_record(); + $DB->query("SELECT SUM(Bounty) FROM requests_votes"); + list($TotalBounty) = $DB->next_record(); + $DB->query("SELECT SUM(rv.Bounty) FROM requests_votes AS rv JOIN requests AS r ON r.ID=rv.RequestID WHERE TorrentID>0"); + list($AvailableBounty) = $DB->next_record(); + $DB->query("SELECT SUM(Snatched), COUNT(ID) FROM torrents"); + list($TotalSnatches, $TotalTorrents) = $DB->next_record(); // This is the total number of snatches for torrents that still exist + + + $DB->query("SELECT COUNT(uid) FROM xbt_snatched"); + list($TotalOverallSnatches) = $DB->next_record(); + + if(($PeerStats = $Cache->get_value('stats_peers')) === false) { + $DB->query("SELECT COUNT(fid) FROM xbt_files_users WHERE remaining=0"); + list($TotalSeeders) = $DB->next_record(); + $DB->query("SELECT COUNT(fid) FROM xbt_files_users WHERE remaining>0"); + list($TotalLeechers) = $DB->next_record(); + } else { + list($TotalLeechers,$TotalSeeders) = $PeerStats; + } + $TotalPeers = $TotalLeechers + $TotalSeeders; + $DB->query("SELECT COUNT(ID) FROM users_main WHERE(SELECT COUNT(uid) FROM xbt_files_users WHERE uid=users_main.ID)>0"); + list($TotalPeerUsers) = $DB->next_record(); + $Cache->cache_value('new_economic_stats', + array($TotalUpload,$TotalDownload,$NumUsers,$TotalBounty, + $AvailableBounty,$TotalSnatches,$TotalTorrents, + $TotalOverallSnatches,$TotalSeeders,$TotalPeers, + $TotalPeerUsers), 3600); +} else { + list($TotalUpload,$TotalDownload,$NumUsers,$TotalBounty,$AvailableBounty, + $TotalSnatches,$TotalTorrents,$TotalOverallSnatches,$TotalSeeders, + $TotalPeers,$TotalPeerUsers) = $EconomicStats; +} + +$TotalLeechers = $TotalPeers - $TotalSeeders; + +?> +
    +
    +
    Overall stats
    +
    +
      +
    • Total upload:
    • +
    • Total download:
    • +
    • Total buffer:
    • +
      +
    • Mean ratio:
    • +
    • Mean upload:
    • +
    • Mean download:
    • +
    • Mean buffer:
    • +
      +
    • Total request bounty:
    • +
    • Available request bounty:
    • +
    +
    +
    +
    +
    +
    Swarms and snatches
    +
    +
      +
    • Total seeders:
    • +
    • Total leechers:
    • +
    • Total peers:
    • +
    • Total snatches:
    • +
    • Seeder/leecher ratio:
    • +
    • Seeder/snatch ratio:
    • +
      +
    • Mean seeders per torrent:
    • +
    • Mean leechers per torrent:
    • +
    • Mean snatches per torrent:
    • +
      +
    • Mean seeding per user:
    • +
    • Mean leeching per user:
    • +
    • Mean snatches per user:
    • +
      +
    • Total users in at least 1 swarm:
    • +
    • Mean seeding per user in at least 1 swarm:
    • +
    • Mean leeching per user in at least 1 swarm:
    • +
    • Mean snatches per user in at least 1 swarm:
    • +
    +
    +
    +
    + diff --git a/sections/tools/data/invite_pool.php b/sections/tools/data/invite_pool.php new file mode 100644 index 00000000..5e170718 --- /dev/null +++ b/sections/tools/data/invite_pool.php @@ -0,0 +1,105 @@ +query("DELETE FROM invites WHERE InviteKey='".db_string($_POST['invitekey'])."'"); +} + +if(!empty($_GET['search'])) { + $Search = db_string($_GET['search']); +} else { + $Search = ""; +} + +$sql = "SELECT + SQL_CALC_FOUND_ROWS + um.ID, + um.Username, + um.PermissionID, + um.Enabled, + ui.Donor, + ui.Warned, + i.InviteKey, + i.Expires, + i.Email + FROM invites as i + JOIN users_main AS um ON um.ID=i.InviterID + JOIN users_info AS ui ON ui.UserID=um.ID "; +if($Search) { + $sql .= "WHERE i.Email LIKE '%$Search%' "; +} +$sql .= "ORDER BY i.Expires DESC LIMIT $Limit"; +$RS = $DB->query($sql); + +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); + +$DB->set_query_id($RS); +?> +
    +

    unused invites have been sent.

    +
    +
    +
    +
    + + + + + +
    Email: + + +   + +
    +
    +
    + + + + + + + + + + + +next_record()) { + $Row = ($Row == 'b') ? 'a' : 'b'; +?> + + + + + + + + + + +
    InviterEmailInviteCodeExpiresControls
    +
    + + + + +
    +
    + + diff --git a/sections/tools/data/opcode_stats.php b/sections/tools/data/opcode_stats.php new file mode 100644 index 00000000..46c6df47 --- /dev/null +++ b/sections/tools/data/opcode_stats.php @@ -0,0 +1,145 @@ + +
    +
    +
    +
    + + +
    + + + + + + + + + + + + +
    Enable: + /> + + + /> + + +
    Controls: + + + + + + +
    + +
    +
    +
    +

    + + + + + + + + + + + + + + + + + + + + + + + + +
    Status
    Total Storage:Used Storage: (%)Free Storage: (%)
    Cached Scripts:Removed Scripts:Cached Keys:N/A
    +

    + + + + + + + +'; +} +$Row = 'a'; // For the pretty colours +foreach ($CachedScripts as $Script) { + list($FilePath, $Modified, $Size, $Reloads, $Uses, $Hits) = array_values($Script); + $Row = ($Row == 'a') ? 'b' : 'a'; +?> + + + + + + + +
    File PathAgeSizeHits
    No scripts cached.
    +
    + diff --git a/sections/tools/data/registration_log.php b/sections/tools/data/registration_log.php new file mode 100644 index 00000000..79c5c378 --- /dev/null +++ b/sections/tools/data/registration_log.php @@ -0,0 +1,95 @@ +query("SELECT + SQL_CALC_FOUND_ROWS + m.ID, + m.IP, + m.Email, + m.Username, + m.PermissionID, + m.Uploaded, + m.Downloaded, + m.Enabled, + i.Donor, + i.Warned, + i.JoinDate, + (SELECT COUNT(h1.UserID) FROM users_history_ips AS h1 WHERE h1.IP=m.IP) AS Uses, + im.ID, + im.IP, + im.Email, + im.Username, + im.PermissionID, + im.Uploaded, + im.Downloaded, + im.Enabled, + ii.Donor, + ii.Warned, + ii.JoinDate, + (SELECT COUNT(h2.UserID) FROM users_history_ips AS h2 WHERE h2.IP=im.IP) AS InviterUses + FROM users_main AS m + LEFT JOIN users_info AS i ON i.UserID=m.ID + LEFT JOIN users_main AS im ON i.Inviter = im.ID + LEFT JOIN users_info AS ii ON i.Inviter = ii.UserID + WHERE i.JoinDate > '".time_minus(3600*24*3)."' + ORDER BY i.Joindate DESC LIMIT $Limit"); +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); +$DB->set_query_id($RS); + +if($DB->record_count()) { +?> + + + + + + + + + + +next_record()) { + $Row = ($IP == $InviterIP) ? 'a' : 'b'; +?> + + + + + + + + + +
    UserRatioEmailIPHostRegistered


    + + [H|S]
    + + [H|S]
    +
    + + [H|S]
    + + [H|S]
    +
    +
    + +

    + + +

    There have been no new registrations in the past 72 hours.

    + diff --git a/sections/tools/data/service_stats.php b/sections/tools/data/service_stats.php new file mode 100644 index 00000000..a5cdc208 --- /dev/null +++ b/sections/tools/data/service_stats.php @@ -0,0 +1,279 @@ +flush(); +} +$DB->query('SHOW GLOBAL STATUS'); +$DBStats =$DB->to_array('Variable_name'); +$MemStats = $Cache->getStats(); + +show_header("Service Stats"); +?> + +
    +
    + + + + + + + + + + + 0.7) { echo ' class="invalid" '; } ?>>Database: + + + + + + + + + + + + + + + + + + + + + + + + 0.85) { echo ' class="invalid" title="Evictions begin when storage exceeds 85%" '; } ?>>Cache Storage: + + + + + + + + +
    Service
    Threads (Active)
    Cache: (100.000%)
    (%)
    Connections
    Cache:
    Database:
    Special
    Cache Current Index:
    Cache Total Index:
    (%)
    Utilities
    Cache: +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + >Cache: + + + + + + + + + + + + + + + + + + >Cache Increment: + + + + >Cache Decrement: + + + + + 0 && $MemStats['cas_hits']/($MemStats['cas_hits']+$MemStats['cas_misses']) < 0.7) { echo ' class="invalid" title="More than 30% of the issued CAS commands were unnecessary wasting time and resources." '; } elseif ($MemStats['cas_hits'] == 0) { echo ' class="notice" title="Disable CAS with the -C parameter and save resources since it is not used." '; } ?>>Cache: + + + + + + + + + >Cache: + + + + + + + + + + $MemStats['uptime']/7*24*3600) { echo ' class="invalid" title="Flushing the cache on a regular basis defeats the benefits of it, look into using cache transactions, or deletes instead of global flushing where possible." '; } ?>>Cache Flushes: + + + + 0) { echo ' class="invalid" '; } ?>>Cache Evicted: + + + + $DBStats['Questions']['Value']/7500) { echo ' class="invalid" title="1/7500 queries is allowed to be slow to minimize performance impact." '; } ?>>Database Slow: + + + + + + + + + + + + + + + + + + + + + +
    Activity
    Total Reads
    Cache:
    Database:
    Total Writes
    Cache:
    Database:
    Get/Select (Success)
    (%)
    Database: (100.000%)
    Set/Insert (Success)
    Cache: (100.000%)
    Database: (100.000%)
    Increment/Decrement (Success)
    (%)
    (%)
    CAS/Update (Success)
    ( 0) { echo number_format(($MemStats['cas_hits']/($MemStats['cas_hits']+$MemStats['cas_misses']))*100, 3); } else { echo '0.000'; }?>%)
    Database: (100.000%)
    Deletes (Success)
    (%)
    Database: (100.000%)
    Special
    Data Read
    Cache:
    Database:
    Data Write
    Cache:
    Database:
    +
    +
    + + + + + + + >Cache: + + + + + + + + + >Cache: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Concurrency
    Total Reads
    /s
    Database:/s
    Total Writes
    /s
    Database:/s
    Get/Select
    Cache:/s
    Database:/s
    Set/Insert
    Cache:/s
    Database:/s
    Increment/Decrement
    Cache Increment:/s
    Cache Decrement:/s
    CAS/Updates
    Cache:/s
    Database:/s
    Deletes
    Cache:/s
    Database:/s
    Special
    Cache Flushes:/s
    Cache Evicted:/s
    Database Slow:/s
    Data Read
    Cache:/s
    Database:/s
    Data Write
    Cache:/s
    Database:/s
    +
    +
    + diff --git a/sections/tools/data/special_users.php b/sections/tools/data/special_users.php new file mode 100644 index 00000000..2a75b956 --- /dev/null +++ b/sections/tools/data/special_users.php @@ -0,0 +1,38 @@ + +
    +query("SELECT + m.ID, + m.Username, + m.PermissionID, + m.Enabled, + i.Donor, + i.Warned + FROM users_main AS m + LEFT JOIN users_info AS i ON i.UserID=m.ID + WHERE m.CustomPermissions != '' + AND m.CustomPermissions != 'a:0:{}'"); +if($DB->record_count()) { +?> + + + + + +next_record()) { +?> + + + + + +
    UserAccess
    Manage
    + +

    There are no special users.

    + +
    + diff --git a/sections/tools/data/torrent_stats.php b/sections/tools/data/torrent_stats.php new file mode 100644 index 00000000..dc3933dc --- /dev/null +++ b/sections/tools/data/torrent_stats.php @@ -0,0 +1,72 @@ +get_value('new_torrent_stats')) { + $DB->query("SELECT COUNT(ID), SUM(Size), SUM(FileCount) FROM torrents"); + list($TorrentCount, $TotalSize, $TotalFiles) = $DB->next_record(); + $DB->query("SELECT COUNT(ID) FROM users_main WHERE Enabled='1'"); + list($NumUsers) = $DB->next_record(); + $DB->query("SELECT COUNT(ID), SUM(Size), SUM(FileCount) FROM torrents WHERE Time > SUBDATE('".sqltime()."', INTERVAL 1 DAY)"); + list($DayNum, $DaySize, $DayFiles) = $DB->next_record(); + $DB->query("SELECT COUNT(ID), SUM(Size), SUM(FileCount) FROM torrents WHERE Time > SUBDATE('".sqltime()."', INTERVAL 7 DAY)"); + list($WeekNum, $WeekSize, $WeekFiles) = $DB->next_record(); + $DB->query("SELECT COUNT(ID), SUM(Size), SUM(FileCount) FROM torrents WHERE Time > SUBDATE('".sqltime()."', INTERVAL 30 DAY)"); + list($MonthNum, $MonthSize, $MonthFiles) = $DB->next_record(); + $Cache->cache_value('new_torrent_stats',array($TorrentCount,$TotalSize,$TotalFiles, + $NumUsers,$DayNum,$DaySize,$DayFiles, + $WeekNum,$WeekSize,$WeekFiles,$MonthNum, + $MonthSize,$MonthFiles),3600); +} else { + list($TorrentCount,$TotalSize,$TotalFiles,$NumUsers,$DayNum,$DaySize,$DayFiles, + $WeekNum,$WeekSize,$WeekFiles,$MonthNum,$MonthSize,$MonthFiles) = $TorrentStats; +} + +?> +
    +
    +
    Overall stats
    +
    +
      +
    • Total torrents:
    • +
    • Total size:
    • +
    • Total files:
    • +
      +
    • Mean torrents per user:
    • +
    • Mean torrent size:
    • +
    • Mean files per torrent:
    • +
    • Mean filesize:
    • +
    +
    +
    +
    +
    +
    Upload frequency
    +
    +
      +
    • Torrents today:
    • +
    • Size today:
    • +
    • Files today:
    • +
      +
    • Torrents this week:
    • +
    • Size this week:
    • +
    • Files this week:
    • +
      +
    • Torrents per day this week:
    • +
    • Size per day this week:
    • +
    • Files per day this week:
    • +
      +
    • Torrents this month:
    • +
    • Size this month:
    • +
    • Files this month:
    • +
      +
    • Torrents per day this month:
    • +
    • Size per day this month:
    • +
    • Files per day this month:
    • +
    +
    +
    +
    + diff --git a/sections/tools/data/upscale_pool.php b/sections/tools/data/upscale_pool.php new file mode 100644 index 00000000..f23a0b4d --- /dev/null +++ b/sections/tools/data/upscale_pool.php @@ -0,0 +1,82 @@ +query("SELECT + SQL_CALC_FOUND_ROWS + m.ID, + m.Username, + m.Uploaded, + m.Downloaded, + m.PermissionID, + m.Enabled, + i.Donor, + i.Warned, + i.JoinDate, + i.RatioWatchEnds, + i.RatioWatchDownload, + m.RequiredRatio + FROM users_main AS m + LEFT JOIN users_info AS i ON i.UserID=m.ID + WHERE i.RatioWatchEnds != '0000-00-00 00:00:00' + AND m.Enabled = '1' + ORDER BY i.RatioWatchEnds ASC LIMIT $Limit"); +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); +$DB->query("SELECT COUNT(UserID) FROM users_info WHERE BanDate != '0000-00-00 00:00:00' AND BanReason = '2'"); +list($TotalDisabled) = $DB->next_record(); +$DB->set_query_id($RS); + +if($DB->record_count()) { +?> +
    +

    There are currently users queued by the system and already disabled.

    +
    + + + + + + + + + + + + + + +next_record()) { + $Row = ($Row == 'b') ? 'a' : 'b'; + +?> + + + + + + + + + + + + + +
    UserUpDownRatioRequired RatioDefecitGambleRegisteredRemainingLifespan
    $Uploaded) { echo get_size(($Downloaded*$RequiredRatio)-$Uploaded);}?>
    + + +

    There are currently no users on ratio watch.

    + diff --git a/sections/tools/data/user_flow.php b/sections/tools/data/user_flow.php new file mode 100644 index 00000000..a6f55bf4 --- /dev/null +++ b/sections/tools/data/user_flow.php @@ -0,0 +1,146 @@ +get_value('users_timeline')) { + $DB->query("SELECT DATE_FORMAT(JoinDate,'%b \'%y') AS Month, COUNT(UserID) FROM users_info GROUP BY Month ORDER BY JoinDate DESC LIMIT 1, 12"); + $TimelineIn = array_reverse($DB->to_array()); + $DB->query("SELECT DATE_FORMAT(BanDate,'%b \'%y') AS Month, COUNT(UserID) FROM users_info GROUP BY Month ORDER BY BanDate DESC LIMIT 1, 12"); + $TimelineOut = array_reverse($DB->to_array()); + foreach($TimelineIn as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + foreach($TimelineOut as $Month) { + list($Label,$Amount) = $Month; + if ($Amount > $Max) { + $Max = $Amount; + } + } + foreach($TimelineIn as $Month) { + list($Label,$Amount) = $Month; + $Labels[] = $Label; + $InFlow[] = number_format(($Amount/$Max)*100,4); + } + foreach($TimelineOut as $Month) { + list($Label,$Amount) = $Month; + $OutFlow[] = number_format(($Amount/$Max)*100,4); + } + $Cache->cache_value('users_timeline',array($Labels,$InFlow,$OutFlow,$Max),mktime(0,0,0,date('n')+1,2)); + } +} +//End timeline generation + + +define('DAYS_PER_PAGE', 100); +list($Page,$Limit) = page_limit(DAYS_PER_PAGE); + +$RS = $DB->query("SELECT + SQL_CALC_FOUND_ROWS + j.Date, + DATE_FORMAT(j.Date,'%Y-%m') AS Month, + CASE ISNULL(j.Flow) + WHEN 0 THEN j.Flow + ELSE '0' + END AS Joined, + CASE ISNULL(m.Flow) + WHEN 0 THEN m.Flow + ELSE '0' + END AS Manual, + CASE ISNULL(r.Flow) + WHEN 0 THEN r.Flow + ELSE '0' + END AS Ratio, + CASE ISNULL(i.Flow) + WHEN 0 THEN i.Flow + ELSE '0' + END AS Inactivity + FROM ( + SELECT + DATE_FORMAT(JoinDate,'%Y-%m-%d') AS Date, + COUNT(UserID) AS Flow + FROM users_info + WHERE JoinDate != '0000-00-00 00:00:00' + GROUP BY Date + ) AS j + LEFT JOIN ( + SELECT + DATE_FORMAT(BanDate,'%Y-%m-%d') AS Date, + COUNT(UserID) AS Flow + FROM users_info + WHERE BanDate != '0000-00-00 00:00:00' + AND BanReason = '1' + GROUP BY Date + ) AS m ON j.Date=m.Date + LEFT JOIN ( + SELECT + DATE_FORMAT(BanDate,'%Y-%m-%d') AS Date, + COUNT(UserID) AS Flow + FROM users_info + WHERE BanDate != '0000-00-00 00:00:00' + AND BanReason = '2' + GROUP BY Date + ) AS r ON j.Date=r.Date + LEFT JOIN ( + SELECT + DATE_FORMAT(BanDate,'%Y-%m-%d') AS Date, + COUNT(UserID) AS Flow + FROM users_info + WHERE BanDate != '0000-00-00 00:00:00' + AND BanReason = '3' + GROUP BY Date + ) AS i ON j.Date=i.Date + ORDER BY j.Date DESC + LIMIT $Limit"); +$DB->query("SELECT FOUND_ROWS()"); +list($Results) = $DB->next_record(); +$DB->set_query_id($RS); + +show_header('User Flow'); +?> +
    + +
    + +
    + + + + + + + + + + + + +next_record()) { + $TotalOut = $Ratio + $Inactivity + $Manual; + $TotalGrowth = $Joined - $TotalOut; +?> + + + + + + + + + + +
    Date(+) Joined(-) Manual(-) Ratio(-) Inactivity(-) TotalNet Growth
    + +
    + diff --git a/sections/tools/index.php b/sections/tools/index.php new file mode 100644 index 00000000..e427180a --- /dev/null +++ b/sections/tools/index.php @@ -0,0 +1,368 @@ +query("UPDATE news SET Title='".db_string($_POST['title'])."', Body='".db_string($_POST['body'])."' WHERE ID='".db_string($_POST['newsid'])."'"); + $Cache->delete_value('news'); + $Cache->delete_value('feed_news'); + } + header('Location: index.php'); + break; + + case 'deletenews': + if(!check_perms('admin_manage_news')){ error(403); } + if(is_number($_GET['id'])){ + authorize(); + $DB->query("DELETE FROM news WHERE ID='".db_string($_GET['id'])."'"); + $Cache->delete_value('news'); + $Cache->delete_value('feed_news'); + + // Deleting latest news + $LatestNews = $Cache->get_value('news_latest_id'); + if ($LatestNews !== FALSE && $LatestNews == $_GET['id']) { + $Cache->delete_value('news_latest_id'); + } + } + header('Location: index.php'); + break; + + case 'takenewnews': + if(!check_perms('admin_manage_news')){ error(403); } + + $DB->query("INSERT INTO news (UserID, Title, Body, Time) VALUES ('$LoggedUser[ID]', '".db_string($_POST['title'])."', '".db_string($_POST['body'])."', '".sqltime()."')"); + $Cache->cache_value('news_latest_id', $DB->inserted_id(), 0); + $Cache->delete_value('news'); + + header('Location: index.php'); + break; + + case 'tokens': + include('managers/tokens.php'); + break; + case 'ocelot': + include('managers/ocelot.php'); + break; + case 'official_tags': + include('managers/official_tags.php'); + break; + + case 'permissions': + if (!check_perms('admin_manage_permissions')) { error(403); } + + if (!empty($_REQUEST['id'])) { + $Val->SetFields('name',true,'string','You did not enter a valid name for this permission set.'); + $Val->SetFields('level',true,'number','You did not enter a valid level for this permission set.'); + $Val->SetFields('maxcollages',true,'number','You did not enter a valid number of personal collages.'); + //$Val->SetFields('test',true,'number','You did not enter a valid level for this permission set.'); + + $Values=array(); + if (is_numeric($_REQUEST['id'])) { + $DB->query("SELECT p.ID,p.Name,p.Level,p.Values,p.DisplayStaff,COUNT(u.ID) FROM permissions AS p LEFT JOIN users_main AS u ON u.PermissionID=p.ID WHERE p.ID='".db_string($_REQUEST['id'])."' GROUP BY p.ID"); + list($ID,$Name,$Level,$Values,$DisplayStaff,$UserCount)=$DB->next_record(MYSQLI_NUM, array(3)); + + if($Level > $LoggedUser['Class'] || $_REQUEST['level'] > $LoggedUser['Class']) { + error(403); + } + + + $Values=unserialize($Values); + } + + + + if (!empty($_POST['submit'])) { + $Err = $Val->ValidateForm($_POST); + + if (!is_numeric($_REQUEST['id'])) { + $DB->query("SELECT ID FROM permissions WHERE Level='".db_string($_REQUEST['level'])."'"); + list($DupeCheck)=$DB->next_record(); + + if ($DupeCheck) { + $Err = "There is already a permission class with that level."; + } + } + + $Values=array(); + foreach ($_REQUEST as $Key => $Perms) { + if (substr($Key,0,5)=="perm_") { $Values[substr($Key,5)]= (int)$Perms; } + } + + $Name=$_REQUEST['name']; + $Level=$_REQUEST['level']; + $DisplayStaff=$_REQUEST['displaystaff']; + $Values['MaxCollages']=$_REQUEST['maxcollages']; + + if (!$Err) { + if (!is_numeric($_REQUEST['id'])) { + $DB->query("INSERT INTO permissions (Level,Name,`Values`,DisplayStaff) VALUES ('".db_string($Level)."','".db_string($Name)."','".db_string(serialize($Values))."','".db_string($DisplayStaff)."')"); + } else { + $DB->query("UPDATE permissions SET Level='".db_string($Level)."',Name='".db_string($Name)."',`Values`='".db_string(serialize($Values))."',DisplayStaff='".db_string($DisplayStaff)."' WHERE ID='".db_string($_REQUEST['id'])."'"); + $Cache->delete_value('perm_'.$_REQUEST['id']); + } + $Cache->delete_value('classes'); + } else { + error($Err); + } + } + + include('managers/permissions_alter.php'); + + } else { + if (!empty($_REQUEST['removeid'])) { + $DB->query("DELETE FROM permissions WHERE ID='".db_string($_REQUEST['removeid'])."'"); + $DB->query("UPDATE users_main SET PermissionID='".USER."' WHERE PermissionID='".db_string($_REQUEST['removeid'])."'"); + + $Cache->delete_value('classes'); + } + + include('managers/permissions_list.php'); + } + + break; + + case 'ip_ban': + //TODO: Clean up db table ip_bans. + include("managers/bans.php"); + break; + + //Data + case 'registration_log': + include('data/registration_log.php'); + break; + + case 'donation_log': + include('data/donation_log.php'); + break; + + + case 'upscale_pool': + include('data/upscale_pool.php'); + break; + + case 'invite_pool': + include('data/invite_pool.php'); + break; + + case 'torrent_stats': + include('data/torrent_stats.php'); + break; + + case 'user_flow': + include('data/user_flow.php'); + break; + + case 'economic_stats': + include('data/economic_stats.php'); + break; + + case 'opcode_stats': + include('data/opcode_stats.php'); + break; + + case 'service_stats': + include('data/service_stats.php'); + break; + + case 'database_specifics': + include('data/database_specifics.php'); + break; + + case 'special_users': + include('data/special_users.php'); + break; + + + case 'browser_support': + include('data/browser_support.php'); + break; + //END Data + + //Misc + case 'update_geoip': + include('misc/update_geoip.php'); + break; + + case 'dupe_ips': + include('misc/dupe_ip.php'); + break; + + case 'clear_cache': + include('misc/clear_cache.php'); + break; + + case 'create_user': + include('misc/create_user.php'); + break; + + case 'manipulate_tree': + include('misc/manipulate_tree.php'); + break; + + case 'recommendations': + include('misc/recommendations.php'); + break; + + case 'analysis': + include('misc/analysis.php'); + break; + + case 'sandbox1': + include('misc/sandbox1.php'); + break; + + case 'sandbox2': + include('misc/sandbox2.php'); + break; + + case 'sandbox3': + include('misc/sandbox3.php'); + break; + + case 'sandbox4': + include('misc/sandbox4.php'); + break; + + case 'sandbox5': + include('misc/sandbox5.php'); + break; + + case 'sandbox6': + include('misc/sandbox6.php'); + break; + + case 'sandbox7': + include('misc/sandbox7.php'); + break; + + case 'sandbox8': + include('misc/sandbox8.php'); + break; + + case 'public_sandbox': + include('misc/public_sandbox.php'); + break; + + case 'mod_sandbox': + if(check_perms('users_mod')) { + include('misc/mod_sandbox.php'); + } else { + error(403); + } + break; + + default: + include(SERVER_ROOT.'/sections/tools/tools.php'); +} +?> diff --git a/sections/tools/managers/bans.php b/sections/tools/managers/bans.php new file mode 100644 index 00000000..7af95a6d --- /dev/null +++ b/sections/tools/managers/bans.php @@ -0,0 +1,158 @@ +query('DELETE FROM ip_bans WHERE ID='.$_POST['id']); + $Bans = $Cache->delete_value('ip_bans'); + } else { //Edit & Create, Shared Validation + $Val->SetFields('start', '1','regex','You must inculde starting IP address.',array('regex'=>'/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i')); + $Val->SetFields('end', '1','regex','You must inculde ending IP address.',array('regex'=>'/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i')); + $Val->SetFields('notes', '1','string','You must inculde a note regarding the reason for the ban.'); + $Err=$Val->ValidateForm($_POST); // Validate the form + if($Err){ error($Err); } + + $Notes = db_string($_POST['notes']); + $Start = ip2unsigned($_POST['start']); //Sanitized by Validation regex + $End = ip2unsigned($_POST['end']); //See above + + if($_POST['submit'] == 'Edit'){ //Edit + if(empty($_POST['id']) || !is_number($_POST['id'])) { + error(404); + } + $DB->query("UPDATE ip_bans SET + FromIP=$Start, + ToIP='$End', + Reason='$Notes' + WHERE ID='".$_POST['id']."'"); + $Bans = $Cache->get_value('ip_bans'); + $Cache->begin_transaction(); + $Cache->update_row($_POST['id'], array($_POST['id'], $Start, $End)); + $Cache->commit_transaction(); + } else { //Create + $DB->query("INSERT INTO ip_bans + (FromIP, ToIP, Reason) VALUES + ('$Start','$End', '$Notes')"); + $ID = $DB->inserted_id(); + $Bans = $Cache->get_value('ip_bans'); + $Bans[$ID] = array($ID, $Start, $End); + $Cache->cache_value('ip_bans', $Bans, 0); + } + } +} + +define('BANS_PER_PAGE', '20'); +list($Page,$Limit) = page_limit(BANS_PER_PAGE); + +$sql = "SELECT SQL_CALC_FOUND_ROWS ID, FromIP, ToIP, Reason FROM ip_bans AS i "; + +if(!empty($_REQUEST['notes'])) { + $sql .= "WHERE Reason LIKE '%".db_string($_REQUEST['notes'])."%' "; +} + +if(!empty($_REQUEST['ip']) && preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $_REQUEST['ip'])) { + if (!empty($_REQUEST['notes'])) { + $sql .= "AND '".ip2unsigned($_REQUEST['ip'])."' BETWEEN FromIP AND ToIP "; + } else { + $sql .= "WHERE '".ip2unsigned($_REQUEST['ip'])."' BETWEEN FromIP AND ToIP "; + } +} + +$sql .= "ORDER BY FromIP ASC"; +$sql .= " LIMIT ".$Limit; +$Bans = $DB->query($sql); + +$DB->query('SELECT FOUND_ROWS()'); +list($Results) = $DB->next_record(); + +$PageLinks=get_pages($Page,$Results,BANS_PER_PAGE,11); + +$DB->set_query_id($Bans); +show_header('IP Bans'); +?> + +

    IP Bans

    + +
    +
    + + + + + + + + +
    + + + + + + + +
    +
    +
    +
    + +

    Manage

    + + + + + + + + + + + + + + + + + +next_record()){ + $Row = ($Row === 'a' ? 'b' : 'a'); + $Start=long2ip($Start); + $End=long2ip($End); +?> + + + + + + + + + + + + +
    RangeNotesSubmit
    + + + + + + +
    + + + + + + + +
    + + diff --git a/sections/tools/managers/dnu_alter.php b/sections/tools/managers/dnu_alter.php new file mode 100644 index 00000000..1c42ca34 --- /dev/null +++ b/sections/tools/managers/dnu_alter.php @@ -0,0 +1,35 @@ +query('DELETE FROM do_not_upload WHERE ID='.$_POST['id']); +} else { //Edit & Create, Shared Validation + $Val->SetFields('name', '1','string','The name must be set, and has a max length of 40 characters', array('maxlength'=>40, 'minlength'=>1)); + $Val->SetFields('comment', '0','string','The description has a max length of 255 characters', array('maxlength'=>255)); + $Err=$Val->ValidateForm($_POST); // Validate the form + if($Err){ error($Err); } + + $P=array(); + $P=db_array($_POST); // Sanitize the form + + if($_POST['submit'] == 'Edit'){ //Edit + if(!is_number($_POST['id']) || $_POST['id'] == ''){ error(0); } + $DB->query("UPDATE do_not_upload SET + Name='$P[name]', + Comment='$P[comment]', + UserID='$LoggedUser[ID]', + Time='".sqltime()."' + WHERE ID='$P[id]'"); + } else { //Create + $DB->query("INSERT INTO do_not_upload + (Name, Comment, UserID, Time) VALUES + ('$P[name]','$P[comment]','$LoggedUser[ID]','".sqltime()."')"); + } +} + +// Go back +header('Location: tools.php?action=dnu') +?> diff --git a/sections/tools/managers/dnu_list.php b/sections/tools/managers/dnu_list.php new file mode 100644 index 00000000..575d6fdd --- /dev/null +++ b/sections/tools/managers/dnu_list.php @@ -0,0 +1,65 @@ +query("SELECT + d.ID, + d.Name, + d.Comment, + d.UserID, + um.Username, + d.Time + FROM do_not_upload as d + LEFT JOIN users_main AS um ON um.ID=d.UserID + ORDER BY d.Time DESC"); +?> +

    Do Not Uploads

    + + + + + + + +next_record()){ ?> + + + + + + + + + + + + + + + + + + + + + +
    NameCommentAddedSubmit
    + + + + + + + +
    +
    + + +
    Add Do Not Upload
    + + + + + +
    + diff --git a/sections/tools/managers/eb.php b/sections/tools/managers/eb.php new file mode 100644 index 00000000..d826dd17 --- /dev/null +++ b/sections/tools/managers/eb.php @@ -0,0 +1,65 @@ +query("SELECT + eb.ID, + eb.UserID, + eb.Time, + eb.Email, + eb.Comment, + um.Username + FROM email_blacklist AS eb + LEFT JOIN users_main AS um ON um.ID=eb.UserID + ORDER BY eb.Time DESC"); +?> +

    Email Blacklist

    + + + + + + + +next_record()) { ?> + + + + + + + + + + + + + + + + + + + + + +
    EmailCommentAddedSubmit
    + + + + + + + +
    +
    + + +
    Add To Email Blacklist
    + + + + + +
    + diff --git a/sections/tools/managers/eb_alter.php b/sections/tools/managers/eb_alter.php new file mode 100644 index 00000000..aaf1fceb --- /dev/null +++ b/sections/tools/managers/eb_alter.php @@ -0,0 +1,35 @@ +query('DELETE FROM email_blacklist WHERE ID='.$_POST['id']); +} else { //Edit & Create, Shared Validation + $Val->SetFields('email', '1','string','The email must be set', array('minlength'=>1)); + $Val->SetFields('comment', '0','string','The description has a max length of 255 characters', array('maxlength'=>255)); + $Err=$Val->ValidateForm($_POST); // Validate the form + if($Err){ error($Err); } + + $P=array(); + $P=db_array($_POST); // Sanitize the form + + if($_POST['submit'] == 'Edit'){ //Edit + if(!is_number($_POST['id']) || $_POST['id'] == ''){ error(0); } + $DB->query("UPDATE email_blacklist SET + Email='$P[email]', + Comment='$P[comment]', + UserID='$LoggedUser[ID]', + Time='".sqltime()."' + WHERE ID='$P[id]'"); + } else { //Create + $DB->query("INSERT INTO email_blacklist + (Email, Comment, UserID, Time) VALUES + ('$P[email]','$P[comment]','$LoggedUser[ID]','".sqltime()."')"); + } +} + +// Go back +header('Location: tools.php?action=email_blacklist') +?> diff --git a/sections/tools/managers/forum_alter.php b/sections/tools/managers/forum_alter.php new file mode 100644 index 00000000..c5bcfdd4 --- /dev/null +++ b/sections/tools/managers/forum_alter.php @@ -0,0 +1,58 @@ +query('DELETE FROM forums WHERE ID='.$_POST['id']); +} else { //Edit & Create, Shared Validation + $Val->SetFields('name', '1','string','The name must be set, and has a max length of 40 characters', array('maxlength'=>40, 'minlength'=>1)); + $Val->SetFields('description', '0','string','The description has a max length of 255 characters', array('maxlength'=>255)); + $Val->SetFields('sort', '1','number','Sort must be set'); + $Val->SetFields('categoryid', '1','number','Category must be set'); + $Val->SetFields('minclassread', '1','number','MinClassRead must be set'); + $Val->SetFields('minclasswrite', '1','number','MinClassWrite must be set'); + $Val->SetFields('minclasscreate', '1','number','MinClassCreate must be set'); + $Err=$Val->ValidateForm($_POST); // Validate the form + if($Err){ error($Err); } + + if($P['minclassread'] > $LoggedUser['Class'] || $P['minclasswrite'] > $LoggedUser['Class'] || $P['minclasscreate'] > $LoggedUser['Class']) { + error(403); + } + $P['autolock'] = isset($_POST['autolock'])?'1':'0'; + + if($_POST['submit'] == 'Edit'){ //Edit + if(!is_number($_POST['id']) || $_POST['id'] == ''){ error(0); } + $DB->query("SELECT MinClassRead FROM forums WHERE ID=".$P['id']); + if($DB->record_count() < 1) { + error(404); + } else { + list($MinClassRead) = $DB->next_record(); + if($MinClassRead > $LoggedUser['Class']) { + error(403); + } + } + + $DB->query("UPDATE forums SET + Sort='$P[sort]', + CategoryID='$P[categoryid]', + Name='$P[name]', + Description='$P[description]', + MinClassRead='$P[minclassread]', + MinClassWrite='$P[minclasswrite]', + MinClassCreate='$P[minclasscreate]', + AutoLock='$P[autolock]' + WHERE ID='$P[id]'"); + } else { //Create + $DB->query("INSERT INTO forums + (Sort, CategoryID, Name, Description, MinClassRead, MinClassWrite, MinClassCreate, AutoLock) VALUES + ('$P[sort]', '$P[categoryid]', '$P[name]','$P[description]','$P[minclassread]','$P[minclasswrite]','$P[minclasscreate]','$P[autolock]')"); + } +} + +$Cache->delete('forums_list'); // Clear cache + +// Go back +header('Location: tools.php?action=forum') +?> diff --git a/sections/tools/managers/forum_list.php b/sections/tools/managers/forum_list.php new file mode 100644 index 00000000..58f69982 --- /dev/null +++ b/sections/tools/managers/forum_list.php @@ -0,0 +1,168 @@ + $Class) { + $Name = $Class['Name']; + $Level = $Class['Level']; + $Return.='
    +

    + + +
    +
    +$Uploaded + ) { +?> +
    +
    Ratio watch
    +
    This user is currently on ratio watch, and must upload in the next , or their leeching privileges will be revoked. Amount downloaded while on ratio watch:
    +
    + +
    +
    + Profile + (Hide)  +
    +
    + + This profile is currently empty. +full_format($Info); +} + +?> +
    +
    + 4 && check_paranoia_here('snatched')) { + $RecentSnatches = $Cache->get_value('recent_snatches_'.$UserID); + if(!is_array($RecentSnatches)){ + $DB->query("SELECT + g.ID, + g.Name, + g.WikiImage + FROM xbt_snatched AS s + INNER JOIN torrents AS t ON t.ID=s.fid + INNER JOIN torrents_group AS g ON t.GroupID=g.ID + WHERE s.uid='$UserID' + AND g.CategoryID='1' + AND g.WikiImage <> '' + GROUP BY g.ID + ORDER BY s.tstamp DESC + LIMIT 5"); + $RecentSnatches = $DB->to_array(); + + $Artists = get_artists($DB->collect('ID')); + foreach($RecentSnatches as $Key => $SnatchInfo) { + $RecentSnatches[$Key]['Artist'] = display_artists($Artists[$SnatchInfo['ID']], false, true); + } + $Cache->cache_value('recent_snatches_'.$UserID, $RecentSnatches, 0); //inf cache + } +?> + + + + + + + + + +
    Recent Snatches
    + <?=display_str($RS['Artist'])?><?=display_str($RS['Name'])?> +
    + 4 && check_paranoia_here('uploads')) { + $RecentUploads = $Cache->get_value('recent_uploads_'.$UserID); + if(!is_array($RecentUploads)){ + $DB->query("SELECT + g.ID, + g.Name, + g.WikiImage + FROM torrents_group AS g + INNER JOIN torrents AS t ON t.GroupID=g.ID + WHERE t.UserID='$UserID' + AND g.CategoryID='1' + AND g.WikiImage <> '' + GROUP BY g.ID + ORDER BY t.Time DESC + LIMIT 5"); + $RecentUploads = $DB->to_array(); + $Artists = get_artists($DB->collect('ID')); + foreach($RecentUploads as $Key => $UploadInfo) { + $RecentUploads[$Key]['Artist'] = display_artists($Artists[$UploadInfo['ID']], false, true); + } + $Cache->cache_value('recent_uploads_'.$UserID, $RecentUploads, 0); //inf cache + } +?> + + + + + + + + + +
    Recent Uploads
    + <?=$RU['Artist']?><?=$RU['Name']?> +
    +query("SELECT ID, Name FROM collages WHERE UserID='$UserID' AND CategoryID='0' AND Deleted='0' ORDER BY Featured DESC, Name ASC"); +$Collages = $DB->to_array(); +$FirstCol = true; +foreach ($Collages as $CollageInfo) { + list($CollageID, $CName) = $CollageInfo; + $DB->query("SELECT ct.GroupID, + tg.WikiImage, + tg.CategoryID + FROM collages_torrents AS ct + JOIN torrents_group AS tg ON tg.ID=ct.GroupID + WHERE ct.CollageID='$CollageID' + ORDER BY ct.Sort LIMIT 5"); + $Collage = $DB->to_array(); +?> + + + + + > +$GroupArtists), false, true); + $Name .= $GroupName; +?> + + + +
    + + - see full + + + + +
    + <?=$Name?> +
    + 0) { + include(SERVER_ROOT.'/classes/class_invite_tree.php'); + $Tree = new INVITE_TREE($UserID, array('visible'=>false)); +?> +
    +
    Invite Tree (View)
    + +
    +query("SELECT + r.ID, + r.CategoryID, + r.Title, + r.Year, + r.TimeAdded, + COUNT(rv.UserID) AS Votes, + SUM(rv.Bounty) AS Bounty + FROM requests AS r + LEFT JOIN users_main AS u ON u.ID=UserID + LEFT JOIN requests_votes AS rv ON rv.RequestID=r.ID + WHERE r.UserID = ".$UserID." + AND r.TorrentID = 0 + GROUP BY r.ID + ORDER BY Votes DESC"); + + if($DB->record_count() > 0) { + $Requests = $DB->to_array(); +?> +
    +
    Requests (View)
    + +
    +query("SELECT + SQL_CALC_FOUND_ROWS + ID, + Subject, + Status, + Level, + AssignedToUser, + Date, + ResolverID + FROM staff_pm_conversations + WHERE UserID = $UserID AND (Level <= $UserLevel OR AssignedToUser='".$LoggedUser['ID']."') + ORDER BY Date DESC"); + if ($DB->record_count()) { + $StaffPMs = $DB->to_array(); +?> +
    +
    Staff PMs (View)
    + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + +
    +
    Staff Notes (Edit)
    +
    + + + + Toggle Edit + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    User Info
    Username:
    CustomTitle:
    Class: + +
    Donor:checked="checked" />
    Artist:checked="checked" />
    Visible:checked="checked" />
    Uploaded: + + +
    Downloaded: + + +
    Merge Stats From: + +
    Freeleech Tokens: + +
    Invites:
    First Line Support:
    Reset: + | + | + | + | + +
    + | + +
    Reset all EAC v0.95 Logs To: + +
    New Password: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Warn User
    Warned: + checked="checked" /> +
    Expiration: + +
    Extension: + +
    Reason: + +

    + + +query("SELECT DISTINCT Email, IP FROM users_history_emails WHERE UserID = ".$UserID." ORDER BY Time ASC"); + $Emails = $DB->to_array(); +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    User Privileges
    Disable: + checked="checked" /> + | + checked="checked" /> | + checked="checked" /> | + + checked="checked" /> | + checked="checked" /> | + checked="checked" /> +
    + checked="checked" /> | + checked="checked" /> | + checked="checked" /> | + checked="checked" /> | + checked="checked" /> +
    Hacked: + to + +
    Account: + +
    User Reason: + +
    Restricted Forums (comma-delimited): + +
    Extra Forums (comma-delimited): + +

    + + + + + + + + + + + + +
    Session
    Reset session:
    Log out:
    + + + + + + + + + + + +
    Submit
    Reason: + +
    + +
    +
    + +
    +
    + diff --git a/sections/userhistory/catchup.php b/sections/userhistory/catchup.php new file mode 100644 index 00000000..837d9c00 --- /dev/null +++ b/sections/userhistory/catchup.php @@ -0,0 +1,18 @@ +get_value('subscriptions_user_'.$LoggedUser['ID'])) === false) { + $DB->query('SELECT TopicID FROM users_subscriptions WHERE UserID = '.db_string($LoggedUser['ID'])); + if($UserSubscriptions = $DB->collect(0)) { + $Cache->cache_value('subscriptions_user_'.$LoggedUser['ID'],$UserSubscriptions,0); + } +} +if(!empty($UserSubscriptions)) { + $DB->query("INSERT INTO forums_last_read_topics (UserID, TopicID, PostID) + SELECT '$LoggedUser[ID]', ID, LastPostID FROM + forums_topics + WHERE ID IN (".implode(',',$UserSubscriptions).") + ON DUPLICATE KEY UPDATE PostID=LastPostID"); +} +$Cache->delete_value('subscriptions_user_new_'.$LoggedUser['ID']); +header('Location: userhistory.php?action=subscriptions'); +?> diff --git a/sections/userhistory/catchup_collages.php b/sections/userhistory/catchup_collages.php new file mode 100644 index 00000000..7d0101c8 --- /dev/null +++ b/sections/userhistory/catchup_collages.php @@ -0,0 +1,13 @@ +query("UPDATE users_collage_subs SET LastVisit = NOW() WHERE UserID = ".$LoggedUser['ID'].$Where); +$Cache->delete_value('collage_subs_user_new_'.$LoggedUser['ID']); + +header('Location: userhistory.php?action=subscribed_collages'); +?> diff --git a/sections/userhistory/collage_subscribe.php b/sections/userhistory/collage_subscribe.php new file mode 100644 index 00000000..eab4fc3e --- /dev/null +++ b/sections/userhistory/collage_subscribe.php @@ -0,0 +1,23 @@ +get_value('collage_subs_user_'.$LoggedUser['ID'])) { + $DB->query('SELECT CollageID FROM users_collage_subs WHERE UserID = '.db_string($LoggedUser['ID'])); + $UserSubscriptions = $DB->collect(0); + $Cache->cache_value('collage_subs_user_'.$LoggedUser['ID'],$UserSubscriptions,0); +} + +if(($Key = array_search($_GET['collageid'],$UserSubscriptions)) !== FALSE) { + $DB->query('DELETE FROM users_collage_subs WHERE UserID = '.db_string($LoggedUser['ID']).' AND CollageID = '.db_string($_GET['collageid'])); + unset($UserSubscriptions[$Key]); +} else { + $DB->query("INSERT IGNORE INTO users_collage_subs (UserID, CollageID, LastVisit) VALUES ($LoggedUser[ID], ".db_string($_GET['collageid']).", NOW())"); + array_push($UserSubscriptions, $_GET['collageid']); +} +$Cache->replace_value('collage_subs_user_'.$LoggedUser['ID'], $UserSubscriptions, 0); +$Cache->delete_value('collage_subs_user_new_'.$LoggedUser['ID']); diff --git a/sections/userhistory/email_history.php b/sections/userhistory/email_history.php new file mode 100644 index 00000000..d7fa9576 --- /dev/null +++ b/sections/userhistory/email_history.php @@ -0,0 +1,116 @@ +query("SELECT um.Username, ui.JoinDate, p.Level AS Class FROM users_main AS um JOIN users_info AS ui ON um.ID=ui.UserID JOIN permissions AS p ON p.ID=um.PermissionID WHERE um.ID = $UserID"); +list($Username, $Joined, $Class) = $DB->next_record(); + +if(!check_perms('users_view_email', $Class)) { + error(403); +} + +$UsersOnly = $_GET['usersonly']; + +show_header("Email history for $Username"); + +if ($UsersOnly == 1) { + $DB->query("SELECT + u.Email, + '".sqltime()."' AS Time, + u.IP, + c.Code + FROM users_main AS u + LEFT JOIN users_main AS u2 ON u2.Email = u.Email AND u2.ID != '$UserID' + LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP + WHERE u.ID='$UserID' AND u2.ID > 0 + UNION SELECT + h.Email, + h.Time, + h.IP, + c.Code + FROM users_history_emails AS h + LEFT JOIN users_history_emails AS h2 ON h2.email=h.email and h2.UserID != '$UserID' + LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP + WHERE h.UserID='$UserID' AND h2.UserID>0"/*AND Time<>'0000-00-00 00:00:00'*/." + ORDER BY Time DESC"); +} else { + $DB->query("SELECT + u.Email, + '".sqltime()."' AS Time, + u.IP, + c.Code + FROM users_main AS u + LEFT JOIN geoip_country AS c ON INET_ATON(u.IP) BETWEEN c.StartIP AND c.EndIP + WHERE u.ID='$UserID' + UNION SELECT + h.Email, + h.Time, + h.IP, + c.Code + FROM users_history_emails AS h + LEFT JOIN geoip_country AS c ON INET_ATON(h.IP) BETWEEN c.StartIP AND c.EndIP + WHERE UserID='$UserID' "/*AND Time<>'0000-00-00 00:00:00'*/." + ORDER BY Time DESC"); +} +$History = $DB->to_array(); +?> +

    Email history for

    + + + + + + + + + + $Values){ + if (isset($History[$Key+1])) { + $Values['Time'] = $History[$Key+1]['Time']; + } else { + $Values['Time'] = $Joined; + } +?> + + + + +query("SELECT ue.UserID, Username, ue.Time, ue.IP FROM users_history_emails AS ue, users_main WHERE ue.Email = '".db_string($Values['Email'])."' AND UserID != ".$UserID." AND ID = UserID"); + while (list($UserID2, $Username, $Time, $IP) = $DB->next_record()) { ?> + + + + +query("SELECT Enabled FROM users_main WHERE ID = ".$UserID2); + list($Enabled)=$DB->next_record(); + $DB->set_query_id($ueQuery); +?> + + + + +
    EmailSetIP [H]User
    () [S]
    +
    + diff --git a/sections/userhistory/email_history2.php b/sections/userhistory/email_history2.php new file mode 100644 index 00000000..70ee22bd --- /dev/null +++ b/sections/userhistory/email_history2.php @@ -0,0 +1,321 @@ +query("SELECT um.Username, ui.JoinDate, p.Level AS Class FROM users_main AS um JOIN users_info AS ui ON um.ID=ui.UserID JOIN permissions AS p ON p.ID=um.PermissionID WHERE um.ID = $UserID"); +list($Username, $Joined, $Class) = $DB->next_record(); + +if(!check_perms('users_view_email', $Class)) { + error(403); +} + +$UsersOnly = $_GET['usersonly']; + +show_header("Email history for $Username"); + +// Get current email (and matches) +$DB->query(" + SELECT + m.Email, + '".sqltime()."' AS Time, + m.IP, + GROUP_CONCAT(h.UserID SEPARATOR '|') AS UserIDs, + GROUP_CONCAT(h.Time SEPARATOR '|') AS UserSetTimes, + GROUP_CONCAT(h.IP SEPARATOR '|') AS UserIPs, + GROUP_CONCAT(m2.Username SEPARATOR '|') AS Usernames, + GROUP_CONCAT(m2.Enabled SEPARATOR '|') AS UsersEnabled, + GROUP_CONCAT(i.Donor SEPARATOR '|') AS UsersDonor, + GROUP_CONCAT(i.Warned SEPARATOR '|') AS UsersWarned + FROM users_main AS m + LEFT JOIN users_history_emails AS h ON h.Email=m.Email AND h.UserID<>m.ID + LEFT JOIN users_main AS m2 ON m2.ID=h.UserID + LEFT JOIN users_info AS i ON i.UserID=h.UserID + WHERE m.ID='$UserID'" +); +$CurrentEmail = array_shift($DB->to_array()); + +// Get historic emails (and matches) +$DB->query(" + SELECT + h2.Email, + h2.Time, + h2.IP, + h3.UserID AS UserIDs, + h3.Time AS UserSetTimes, + h3.IP AS UserIPs, + m3.Username AS Usernames, + m3.Enabled AS UsersEnabled, + i2.Donor AS UsersDonor, + i2.Warned AS UsersWarned + FROM users_history_emails AS h2 + LEFT JOIN users_history_emails AS h3 ON h3.Email=h2.Email AND h3.UserID<>h2.UserID + LEFT JOIN users_main AS m3 ON m3.ID=h3.UserID + LEFT JOIN users_info AS i2 ON i2.UserID=h3.UserID + WHERE h2.UserID='$UserID' + ORDER BY Time DESC" +); +$History = $DB->to_array(); + +// Current email +$Current['Email'] = $CurrentEmail['Email']; +$Current['StartTime'] = $History[0]['Time']; +$Current['CurrentIP'] = $CurrentEmail['IP']; +$Current['IP'] = $History[(count($History) - 1)]['IP']; + +// Matches for current email +if ($CurrentEmail['Usernames'] != '') { + $UserIDs=explode('|', $CurrentEmail['UserIDs']); + $Usernames=explode('|', $CurrentEmail['Usernames']); + $UsersEnabled=explode('|', $CurrentEmail['UsersEnabled']); + $UsersDonor=explode('|', $CurrentEmail['UsersDonor']); + $UsersWarned=explode('|', $CurrentEmail['UsersWarned']); + $UserSetTimes=explode('|', $CurrentEmail['UserSetTimes']); + $UserIPs=explode('|', $CurrentEmail['UserIPs']); + + foreach($UserIDs as $Key => $Val) { + $CurrentMatches[$Key]['Username'] = '  » '.format_username($Val, $Usernames[$Key], $UsersDonor[$Key], $UsersWarned[$Key], $UsersEnabled[$Key] == 2 ? false : true); + $CurrentMatches[$Key]['IP'] = $UserIPs[$Key]; + $CurrentMatches[$Key]['EndTime'] = $UserSetTimes[$Key]; + } +} + +// Email history records +if (count($History) == 1) { + $Invite['Email'] = $History[0]['Email']; + $Invite['EndTime'] = $Joined; + $Invite['AccountAge'] = date(time() + time() - strtotime($Joined)); // Same as EndTime but without ' ago' + $Invite['IP'] = $History[0]['IP']; + if ($Current['StartTime'] == '0000-00-00 00:00:00') { $Current['StartTime'] = $Joined; } +} else { + foreach ($History as $Key => $Val) { + if ($History[$Key+1]['Time'] == '0000-00-00 00:00:00' && $Val['Time'] != '0000-00-00 00:00:00') { + // Invited email + $Invite['Email'] = $Val['Email']; + $Invite['EndTime'] = $Joined; + $Invite['AccountAge'] = date(time() + time() - strtotime($Joined)); // Same as EndTime but without ' ago' + $Invite['IP'] = $Val['IP']; + + } elseif ($History[$Key-1]['Email'] != $Val['Email'] && $Val['Time'] != '0000-00-00 00:00:00') { + // Old email + $i=1; + while($Val['Email'] == $History[$Key+$i]['Email']) { + $i++; + } + $Old[$Key]['StartTime'] = (isset($History[$Key+$i]) && $History[$Key+$i]['Time'] != '0000-00-00 00:00:00') ? $History[$Key+$i]['Time'] : $Joined; + $Old[$Key]['EndTime'] = $Val['Time']; + $Old[$Key]['IP'] = $Val['IP']; + $Old[$Key]['ElapsedTime'] = date(time() + strtotime($Old[$Key]['EndTime']) - strtotime($Old[$Key]['StartTime'])); + $Old[$Key]['Email'] = $Val['Email']; + + } else { + // Shouldn't have to be here but I'll leave it anyway + $Other[$Key]['StartTime'] = (isset($History[$Key+$i])) ? $History[$Key+$i]['Time'] : $Joined; + $Other[$Key]['EndTime'] = $Val['Time']; + $Other[$Key]['IP'] = $Val['IP']; + $Other[$Key]['ElapsedTime'] = date(time() + strtotime($Other[$Key]['EndTime']) - strtotime($Other[$Key]['StartTime'])); + $Other[$Key]['Email'] = $Val['Email']; + } + + if ($Val['Usernames'] != '') { + // Match with old email + $OldMatches[$Key]['Email'] = $Val['Email']; + $OldMatches[$Key]['Username'] = '  » '.format_username($Val['UserIDs'], $Val['Usernames'], $Val['UsersDonor'], $Val['UsersWarned'], $Val['UsersEnabled'] == 2 ? false : true); + $OldMatches[$Key]['EndTime'] = $Val['UserSetTimes']; + $OldMatches[$Key]['IP'] = $Val['UserIPs']; + } + } +} + +// Clean up arrays +if ($Old) { + $Old = array_reverse(array_reverse($Old)); + $LastOld = count($Old)-1; + if ($Old[$LastOld]['StartTime'] != $Invite['EndTime']) { + // Make sure the timeline is intact (invite email was used as email for the account in the beginning) + $Old[$LastOld+1]['Email'] = $Invite['Email']; + $Old[$LastOld+1]['StartTime'] = $Invite['EndTime']; + $Old[$LastOld+1]['EndTime'] = $Old[$LastOld]['StartTime']; + $Old[$LastOld+1]['ElapsedTime'] = date(time()+strtotime($Old[$LastOld+1]['EndTime'] )-strtotime($Old[$LastOld+1]['StartTime'])); + $Old[$LastOld+1]['IP'] = $Invite['IP']; + } +} + +// Start page with current email +?> +

    Email history for

    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0) { + if (isset($Matches)) { + echo $Matches; + unset($Matches); + unset($MatchCount); + } + } + } +} +// Invite email (always there) +?> + + + + + + + + + + + + + + + + + + + + + + + + +
    Current emailStartEndCurrent IP [H]Set from IP
    + () [S] [WI]
    + +
    + () [S] [WI]
    + +
    + () [S] [WI]
    + +
    Old emailsStartEndElapsedSet from IP
    0) ? ' ('.$MatchCount.')' : '')?> + () [S] [WI]
    + +
    Invite emailStartEndAge of accountSignup IP
    0) ? ' ('.$MatchCount.')' : '')?>Never + () [S] [WI]
    + +
    +
    + diff --git a/sections/userhistory/index.php b/sections/userhistory/index.php new file mode 100644 index 00000000..0eb7cd6e --- /dev/null +++ b/sections/userhistory/index.php @@ -0,0 +1,115 @@ + diff --git a/sections/userhistory/ip_history.php b/sections/userhistory/ip_history.php new file mode 100644 index 00000000..8cfe8bfc --- /dev/null +++ b/sections/userhistory/ip_history.php @@ -0,0 +1,151 @@ +query("SELECT um.Username, p.Level AS Class FROM users_main AS um LEFT JOIN permissions AS p ON p.ID=um.PermissionID WHERE um.ID = ".$UserID); +list($Username, $Class) = $DB->next_record(); + +if(!check_perms('users_view_ips', $Class)) { + error(403); +} + +$UsersOnly = $_GET['usersonly']; + +show_header("IP history for $Username"); +?> + +
    +query("SELECT SQL_CALC_FOUND_ROWS + h1.IP, + h1.StartTime, + h1.EndTime, + GROUP_CONCAT(h2.UserID SEPARATOR '|'), + GROUP_CONCAT(h2.StartTime SEPARATOR '|'), + GROUP_CONCAT(h2.EndTime SEPARATOR '|'), + GROUP_CONCAT(um2.Username SEPARATOR '|'), + GROUP_CONCAT(um2.Enabled SEPARATOR '|'), + GROUP_CONCAT(ui2.Donor SEPARATOR '|'), + GROUP_CONCAT(ui2.Warned SEPARATOR '|') + FROM users_history_ips AS h1 + LEFT JOIN users_history_ips AS h2 ON h2.IP=h1.IP AND h2.UserID!=$UserID + LEFT JOIN users_main AS um2 ON um2.ID=h2.UserID + LEFT JOIN users_info AS ui2 ON ui2.UserID=h2.UserID + WHERE h1.UserID='$UserID' + AND h2.UserID>0 + GROUP BY h1.IP, h1.StartTime + ORDER BY h1.StartTime DESC LIMIT $Limit"); +} else { + $RS = $DB->query("SELECT SQL_CALC_FOUND_ROWS + h1.IP, + h1.StartTime, + h1.EndTime, + GROUP_CONCAT(h2.UserID SEPARATOR '|'), + GROUP_CONCAT(h2.StartTime SEPARATOR '|'), + GROUP_CONCAT(h2.EndTime SEPARATOR '|'), + GROUP_CONCAT(um2.Username SEPARATOR '|'), + GROUP_CONCAT(um2.Enabled SEPARATOR '|'), + GROUP_CONCAT(ui2.Donor SEPARATOR '|'), + GROUP_CONCAT(ui2.Warned SEPARATOR '|') + FROM users_history_ips AS h1 + LEFT JOIN users_history_ips AS h2 ON h2.IP=h1.IP AND h2.UserID!=$UserID + LEFT JOIN users_main AS um2 ON um2.ID=h2.UserID + LEFT JOIN users_info AS ui2 ON ui2.UserID=h2.UserID + WHERE h1.UserID='$UserID' + GROUP BY h1.IP, h1.StartTime + ORDER BY h1.StartTime DESC LIMIT $Limit"); +} +$DB->query("SELECT FOUND_ROWS()"); +list($NumResults) = $DB->next_record(); +$DB->set_query_id($RS); + +$Pages=get_pages($Page,$NumResults,IPS_PER_PAGE,9); + +?> +

    IP history for

    + + + + + + + + +to_array(); +foreach($Results as $Index => $Result) { + list($IP, $StartTime, $EndTime, $UserIDs, $UserStartTimes, $UserEndTimes, $Usernames, $UsersEnabled, $UsersDonor, $UsersWarned) = $Result; + + $HasDupe = false; + $UserIDs = explode('|', $UserIDs); + if(!$EndTime) { $EndTime = sqltime(); } + if($UserIDs[0] != 0){ + $HasDupe = true; + $UserStartTimes = explode('|', $UserStartTimes); + $UserEndTimes = explode('|', $UserEndTimes); + $Usernames = explode('|', $Usernames); + $UsersEnabled = explode('|', $UsersEnabled); + $UsersDonor = explode('|', $UsersDonor); + $UsersWarned = explode('|', $UsersWarned); + } +?> + + + + + + + 10); + foreach ($UserIDs as $Key => $Val) { + if(!$UserEndTimes[$Key]){ $UserEndTimes[$Key] = sqltime(); } +?> + + + + + + + + +
    IP addressStartedEndedElapsed
    + ()
    + + ('.count($UserIDs).')' + : '(0)')?>
      » 
    + +
    + + diff --git a/sections/userhistory/ip_tracker_history.php b/sections/userhistory/ip_tracker_history.php new file mode 100644 index 00000000..27a835cb --- /dev/null +++ b/sections/userhistory/ip_tracker_history.php @@ -0,0 +1,79 @@ +query("SELECT um.Username, p.Level AS Class FROM users_main AS um LEFT JOIN permissions AS p ON p.ID=um.PermissionID WHERE um.ID = ".$UserID); +list($Username, $Class) = $DB->next_record(); + +if(!check_perms('users_view_ips', $Class)) { + error(403); +} + +$UsersOnly = $_GET['usersonly']; + +show_header("Tracker IP history for $Username"); +?> + +
    +query("SELECT IP, fid, tstamp FROM xbt_snatched WHERE uid = ".$UserID." AND IP != '' ORDER BY tstamp DESC LIMIT $Limit"); + +$DB->query("SELECT FOUND_ROWS()"); +list($NumResults) = $DB->next_record(); +$DB->set_query_id($TrackerIps); + +$Pages=get_pages($Page,$NumResults,IPS_PER_PAGE,9); + +?> +

    Tracker IP history for

    + + + + + + + +to_array(); +foreach($Results as $Index => $Result) { + list($IP, $TorrentID, $Time) = $Result; + +?> + + + + + +
    IP addressTorrentTime
    ()
    +
    + +
    + + diff --git a/sections/userhistory/passkey_history.php b/sections/userhistory/passkey_history.php new file mode 100644 index 00000000..5271aa47 --- /dev/null +++ b/sections/userhistory/passkey_history.php @@ -0,0 +1,52 @@ +query("SELECT um.Username, p.Level AS Class FROM users_main AS um LEFT JOIN permissions AS p ON p.ID=um.PermissionID WHERE um.ID = ".$UserID); +list($Username, $Class) = $DB->next_record(); + +if(!check_perms('users_view_keys', $Class)) { + error(403); +} + +show_header("PassKey history for $Username"); + +$DB->query("SELECT + OldPassKey, + NewPassKey, + ChangeTime, + ChangerIP + FROM users_history_passkeys + WHERE UserID=$UserID + ORDER BY ChangeTime DESC"); + +?> +

    Passkey history for

    + + + + + + + +next_record()){ ?> + + + + + + + +
    OldNewChangedIP [H]
    [S]
    + diff --git a/sections/userhistory/password_history.php b/sections/userhistory/password_history.php new file mode 100644 index 00000000..0ea70d10 --- /dev/null +++ b/sections/userhistory/password_history.php @@ -0,0 +1,46 @@ +query("SELECT um.Username, p.Level AS Class FROM users_main AS um LEFT JOIN permissions AS p ON p.ID=um.PermissionID WHERE um.ID = ".$UserID); +list($Username, $Class) = $DB->next_record(); + +if(!check_perms('users_view_keys', $Class)) { + error(403); +} + +show_header("Password reset history for $Username"); + +$DB->query("SELECT + ChangeTime, + ChangerIP + FROM users_history_passwords + WHERE UserID=$UserID + ORDER BY ChangeTime DESC"); + +?> +

    Password reset history for

    + + + + + +next_record()){ ?> + + + + + +
    ChangedIP [H]
    [S]
    + diff --git a/sections/userhistory/post_history.php b/sections/userhistory/post_history.php new file mode 100644 index 00000000..74cda3fe --- /dev/null +++ b/sections/userhistory/post_history.php @@ -0,0 +1,337 @@ +get_value('user_info_'.$UserID)) === FALSE) { + $DB->query("SELECT + m.Username, + m.Enabled, + m.Title, + i.Avatar, + i.Donor, + i.Warned + FROM users_main AS m + JOIN users_info AS i ON i.UserID = m.ID + WHERE m.ID = $UserID"); + + if($DB->record_count() == 0){ // If user doesn't exist + error(404); + } + list($Username, $Enabled, $Title, $Avatar, $Donor, $Warned) = $DB->next_record(); +} else { + extract(array_intersect_key($UserInfo, array_flip(array('Username', 'Enabled', 'Title', 'Avatar', 'Donor', 'Warned')))); +} + +if(check_perms('site_proxy_images') && !empty($Avatar)) { + $Avatar = 'http'.($SSL?'s':'').'://'.SITE_URL.'/image.php?c=1&i='.urlencode($Avatar); +} + +show_header('Post history for '.$Username,'subscriptions,comments,bbcode'); + +if($LoggedUser['CustomForums']) { + unset($LoggedUser['CustomForums']['']); + $RestrictedForums = implode("','", array_keys($LoggedUser['CustomForums'], 0)); +} +$ViewingOwn = ($UserID == $LoggedUser['ID']); +$ShowUnread = ($ViewingOwn && (!isset($_GET['showunread']) || !!$_GET['showunread'])); +$ShowGrouped = ($ViewingOwn && (!isset($_GET['group']) || !!$_GET['group'])); +if($ShowGrouped) { + $sql = 'SELECT + SQL_CALC_FOUND_ROWS + MAX(p.ID) AS ID + FROM forums_posts AS p + LEFT JOIN forums_topics AS t ON t.ID = p.TopicID'; + if($ShowUnread) { + $sql.=' + LEFT JOIN forums_last_read_topics AS l ON l.TopicID = t.ID AND l.UserID = '.$LoggedUser['ID']; + } + $sql .= ' + LEFT JOIN forums AS f ON f.ID = t.ForumID + WHERE p.AuthorID = '.$UserID.' + AND ((f.MinClassRead <= '.$LoggedUser['Class']; + if(!empty($RestrictedForums)) { + $sql.=' + AND f.ID NOT IN (\''.$RestrictedForums.'\')'; + } + $sql .= ')'; + if(!empty($PermittedForums)) { + $sql.=' + OR f.ID IN (\''.$PermittedForums.'\')'; + } + $sql .= ')'; + if($ShowUnread) { + $sql .= ' + AND ((t.IsLocked=\'0\' OR t.IsSticky=\'1\') + AND (l.PostIDquery($sql); + $DB->query("SELECT FOUND_ROWS()"); + list($Results) = $DB->next_record(); + + if($Results > $PerPage*($Page-1)) { + $DB->set_query_id($PostIDs); + $PostIDs = $DB->collect('ID'); + $sql = 'SELECT + p.ID, + p.AddedTime, + p.Body, + p.EditedUserID, + p.EditedTime, + ed.Username, + p.TopicID, + t.Title, + t.LastPostID, + l.PostID AS LastRead, + t.IsLocked, + t.IsSticky + FROM forums_posts as p + LEFT JOIN users_main AS um ON um.ID = p.AuthorID + LEFT JOIN users_info AS ui ON ui.UserID = p.AuthorID + LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID + JOIN forums_topics AS t ON t.ID = p.TopicID + JOIN forums AS f ON f.ID = t.ForumID + LEFT JOIN forums_last_read_topics AS l ON l.UserID = '.$UserID.' AND l.TopicID = t.ID + WHERE p.ID IN ('.implode(',',$PostIDs).') + ORDER BY p.ID DESC'; + $Posts = $DB->query($sql); + } +} else { + $sql = 'SELECT + SQL_CALC_FOUND_ROWS'; + if($ShowGrouped) { + $sql.=' * FROM (SELECT'; + } + $sql .= ' + p.ID, + p.AddedTime, + p.Body, + p.EditedUserID, + p.EditedTime, + ed.Username, + p.TopicID, + t.Title, + t.LastPostID,'; + if($UserID == $LoggedUser['ID']) { + $sql .= ' + l.PostID AS LastRead,'; + } + $sql .= ' + t.IsLocked, + t.IsSticky + FROM forums_posts as p + LEFT JOIN users_main AS um ON um.ID = p.AuthorID + LEFT JOIN users_info AS ui ON ui.UserID = p.AuthorID + LEFT JOIN users_main AS ed ON ed.ID = p.EditedUserID + JOIN forums_topics AS t ON t.ID = p.TopicID + JOIN forums AS f ON f.ID = t.ForumID + LEFT JOIN forums_last_read_topics AS l ON l.UserID = '.$UserID.' AND l.TopicID = t.ID + WHERE p.AuthorID = '.$UserID.' + AND f.MinClassRead <= '.$LoggedUser['Class']; + + if(!empty($RestrictedForums)) { + $sql.=' + AND f.ID NOT IN (\''.$RestrictedForums.'\')'; + } + + if($ShowUnread) { + $sql.=' + AND ((t.IsLocked=\'0\' OR t.IsSticky=\'1\') AND (l.PostIDquery($sql); + + $DB->query("SELECT FOUND_ROWS()"); + list($Results) = $DB->next_record(); + + $DB->set_query_id($Posts); +} + +?> +
    +

    +$Username"; + } + elseif($ShowUnread) { + echo "Unread post history for $Username"; + } + else { + echo "Post history for $Username"; + } +?> +

    + + + +
    + No topics +
    + + +next_record()){ +?> + ' id='post'> + + + + + + + + + + + +
    + + + in + + (New!) + + + + + + + + + + + + [Subscribe] +   + + + +
    + + <?=$Username?>'s avatar + + +
    + full_format($Body)?> + +
    +
    + + « + + Last edited by + + +
    +
    + + + +
    + diff --git a/sections/userhistory/subscribed_collages.php b/sections/userhistory/subscribed_collages.php new file mode 100644 index 00000000..bda46cb3 --- /dev/null +++ b/sections/userhistory/subscribed_collages.php @@ -0,0 +1,307 @@ + s.LastVisit + GROUP BY c.ID"; +} else { + $sql = "SELECT c.ID, + c.Name, + c.NumTorrents, + s.LastVisit + FROM collages AS c + JOIN users_collage_subs AS s ON s.CollageID = c.ID + LEFT JOIN collages_torrents AS ct ON ct.CollageID = c.ID + WHERE s.UserID = ".$LoggedUser['ID']." AND c.Deleted='0' + GROUP BY c.ID"; +} + +$DB->query($sql); +$NumResults = $DB->record_count(); +$CollageSubs = $DB->to_array(); +?> +
    +

    Subscribed collages

    + + + +
    + No subscribed collages +
    +query("SELECT ct.GroupID, + tg.WikiImage, + tg.CategoryID + FROM collages_torrents AS ct + JOIN torrents_group AS tg ON ct.GroupID = tg.ID + WHERE ct.CollageID = $CollageID + AND ct.AddedOn > '$LastVisit' + ORDER BY ct.AddedOn"); + $NewTorrentCount = $DB->record_count(); + //$NewTorrents = $DB->to_array(); + //$Artists = get_artists($GroupID); + + $GroupIDs = $DB->collect('GroupID'); + $CollageDataList=$DB->to_array('GroupID', MYSQLI_ASSOC); + if(count($GroupIDs)>0) { + $TorrentList = get_groups($GroupIDs); + $TorrentList = $TorrentList['matches']; + } else { + $TorrentList = array(); + } + + $Artists = get_artists($GroupIDs); + $Number = 0; + + // foreach ($NewTorrents as $TorrentGroup) { + // list($GroupID, $GroupName, $GroupYear, $ReleaseType, $RecordLabel, $CatalogueNumber, $WikiImage) = $TorrentGroup; + // $DisplayName = display_artists($Artists[$GroupID]); + // $AltName=$GroupName; + foreach ($TorrentList as $GroupID => $Group) { + list($GroupID, $GroupName, $GroupYear, $GroupRecordLabel, $GroupCatalogueNumber, $TagList, $ReleaseType, $GroupVanityHouse, $Torrents, $GroupArtists, $ExtendedArtists) = array_values($Group); + list($GroupID2, $Image, $GroupCategoryID) = array_values($CollageDataList[$GroupID]); + + unset($DisplayName); + + $TagList = explode(' ',str_replace('_','.',$TagList)); + + $TorrentTags = array(); + foreach($TagList as $Tag) { + if(!isset($Tags[$Tag])) { + $Tags[$Tag] = array('name'=>$Tag, 'count'=>1); + } else { + $Tags[$Tag]['count']++; + } + $TorrentTags[]=''.$Tag.''; + } + $PrimaryTag = $TagList[0]; + $TorrentTags = implode(', ', $TorrentTags); + $TorrentTags='
    '.$TorrentTags.'
    '; + + if (!empty($ExtendedArtists[1]) || !empty($ExtendedArtists[4]) || !empty($ExtendedArtists[5]) || !empty($ExtendedArtists[6])) { + unset($ExtendedArtists[2]); + unset($ExtendedArtists[3]); + $DisplayName .= display_artists($ExtendedArtists); + } elseif(count($GroupArtists)>0) { + $DisplayName .= display_artists(array('1'=>$GroupArtists)); + } + $DisplayName .= ''.$GroupName.''; + if($GroupYear>0) { $DisplayName = $DisplayName. ' ['. $GroupYear .']';} + if($GroupVanityHouse) { $DisplayName .= ' [VH]'; } + + // Start an output buffer, so we can store this output in $TorrentTable + ob_start(); + if(count($Torrents)>1 || $GroupCategoryID==1) { +?> + + +
    + +
    + + + + + <?=$AltName?> + + <?=$Categories[$GroupCategoryID-1]?> + + + + + + + + + $Torrent) { + + if ($Torrent['Remastered'] && !$Torrent['RemasterYear']) { + $FirstUnknown = !isset($FirstUnknown); + } + + if($Torrent['RemasterTitle'] != $LastRemasterTitle || $Torrent['RemasterYear'] != $LastRemasterYear || + $Torrent['RemasterRecordLabel'] != $LastRemasterRecordLabel || $Torrent['RemasterCatalogueNumber'] != $LastRemasterCatalogueNumber || $FirstUnknown || $Torrent['Media'] != $LastMedia) { + if($Torrent['Remastered'] && $Torrent['RemasterYear'] != 0) { + + $EditionID++; + + $RemasterName = $Torrent['RemasterYear']; + $AddExtra = " - "; + if($Torrent['RemasterRecordLabel']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterRecordLabel']); $AddExtra=' / '; } + if($Torrent['RemasterCatalogueNumber']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterCatalogueNumber']); $AddExtra=' / '; } + if($Torrent['RemasterTitle']) { $RemasterName .= $AddExtra.display_str($Torrent['RemasterTitle']); $AddExtra=' / '; } + $RemasterName .= $AddExtra.display_str($Torrent['Media']); + +?> + + + + + + + + + + + + [DL] + +   »  + + + + > + + +'.$GroupName.''; + + if(!empty($Torrent['FreeTorrent'])) { + $DisplayName .=' Freeleech!'; + } +?> + + + +
    +
    + + + + [DL + | RP] + + + + + + + > + + + + + + + + + +
    + + ( new torrent) +   + +    [Catch up]   [Unsubscribe] + +
    + + + + + + + + + + + + + + +
    TorrentsSizeSnatchesSeedersLeechers
    + + +
    + diff --git a/sections/userhistory/subscriptions.php b/sections/userhistory/subscriptions.php new file mode 100644 index 00000000..45b83765 --- /dev/null +++ b/sections/userhistory/subscriptions.php @@ -0,0 +1,188 @@ +query($sql); +$DB->query('SELECT FOUND_ROWS()'); +list($NumResults) = $DB->next_record(); + +if($NumResults > $PerPage*($Page-1)) { + $DB->set_query_id($PostIDs); + $PostIDs = $DB->collect('ID'); + $sql = 'SELECT + f.ID AS ForumID, + f.Name AS ForumName, + p.TopicID, + t.Title, + p.Body, + t.LastPostID, + t.IsLocked, + t.IsSticky, + p.ID, + um.ID, + um.Username, + ui.Avatar, + p.EditedUserID, + p.EditedTime, + ed.Username AS EditedUsername + FROM forums_posts AS p + LEFT JOIN forums_topics AS t ON t.ID = p.TopicID + LEFT JOIN forums AS f ON f.ID = t.ForumID + LEFT JOIN users_main AS um ON um.ID = p.AuthorID + LEFT JOIN users_info AS ui ON ui.UserID = um.ID + LEFT JOIN users_main AS ed ON ed.ID = um.ID + WHERE p.ID IN ('.implode(',',$PostIDs).') + ORDER BY f.Name ASC, t.LastPostID DESC'; + $DB->query($sql); +} +?> +
    +

    + + + +
    + No subscribed topics +
    + + +next_record()){ +?> + '> + + + + + + + + + +
    + + > + + + (New!) + + + + + + + [Unsubscribe] +   + + +
    + ]+)+\.(jpg|jpeg|gif|png|tif|tiff|bmp)$/is',$AuthorAvatar)) { ?> + <?=$AuthorName?>'s avatar + + Default avatar + + <?=$AuthorName?>'s avatar + + +
    + full_format($Body) ?> + +

    + Last edited by + + +
    +
    + + + +
    + diff --git a/sections/userhistory/thread_subscribe.php b/sections/userhistory/thread_subscribe.php new file mode 100644 index 00000000..dd10d707 --- /dev/null +++ b/sections/userhistory/thread_subscribe.php @@ -0,0 +1,34 @@ +query('SELECT ID FROM forums WHERE forums.ID = (SELECT ForumID FROM forums_topics WHERE ID = '.db_string($_GET['topicid']).')'); +list($ForumID) = $DB->next_record(); +if(!check_forumperm($ForumID)) { + die(); +} + +if(!$UserSubscriptions = $Cache->get_value('subscriptions_user_'.$LoggedUser['ID'])) { + $DB->query('SELECT TopicID FROM users_subscriptions WHERE UserID = '.db_string($LoggedUser['ID'])); + $UserSubscriptions = $DB->collect(0); + $Cache->cache_value('subscriptions_user_'.$LoggedUser['ID'],$UserSubscriptions,0); +} + +if(($Key = array_search($_GET['topicid'],$UserSubscriptions)) !== FALSE) { + $DB->query('DELETE FROM users_subscriptions WHERE UserID = '.db_string($LoggedUser['ID']).' AND TopicID = '.db_string($_GET['topicid'])); + unset($UserSubscriptions[$Key]); +} else { + $DB->query("INSERT IGNORE INTO users_subscriptions (UserID, TopicID) VALUES ($LoggedUser[ID], ".db_string($_GET['topicid']).")"); + array_push($UserSubscriptions, $_GET['topicid']); +} +$Cache->replace_value('subscriptions_user_'.$LoggedUser['ID'], $UserSubscriptions, 0); +$Cache->delete_value('subscriptions_user_new_'.$LoggedUser['ID']); diff --git a/sections/userhistory/token_history.php b/sections/userhistory/token_history.php new file mode 100644 index 00000000..f530da67 --- /dev/null +++ b/sections/userhistory/token_history.php @@ -0,0 +1,116 @@ +query("SELECT info_hash FROM torrents where ID = $TorrentID"); + if (list($InfoHash) = $DB->next_record(MYSQLI_NUM, FALSE)) { + $DB->query("UPDATE users_freeleeches SET Expired=TRUE WHERE UserID=$UserID AND TorrentID=$TorrentID"); + $Cache->delete_value('users_tokens_'.$UserID); + update_tracker('remove_token', array('info_hash' => rawurlencode($InfoHash), 'userid' => $UserID)); + } + header("Location: userhistory.php?action=token_history&userid=$UserID"); +} + +show_header('Freeleech token history'); + +list($Page,$Limit) = page_limit(25); + +$DB->query("SELECT SQL_CALC_FOUND_ROWS + f.TorrentID, + t.GroupID, + f.Time, + f.Expired, + f.Downloaded, + f.Uses, + g.Name, + t.Format, + t.Encoding + FROM users_freeleeches AS f + JOIN torrents AS t ON t.ID = f.TorrentID + JOIN torrents_group AS g ON g.ID = t.GroupID + WHERE f.UserID = $UserID + ORDER BY f.Time DESC + LIMIT $Limit"); +$Tokens = $DB->to_array(); + +$DB->query("SELECT FOUND_ROWS()"); +list($NumResults) = $DB->next_record(); +$Pages=get_pages($Page, $NumResults, 25); + +?> +

    Freeleech token history for

    + + + + + + + + + + + + +$Name"; + $ArtistName = display_artists($Artists[$GroupID]); + if($ArtistName) { + $Name = $ArtistName.$Name; + } + if($Format && $Encoding) { + $Name.=' ['.$Format.' / '.$Encoding.']'; + } +?> + + + + + + + + + + +
    TorrentTimeExpiredDownloadedTokens Used
    (expire)":''?> +
    + + \ No newline at end of file diff --git a/sections/wiki/add_alias.php b/sections/wiki/add_alias.php new file mode 100644 index 00000000..4bbe8990 --- /dev/null +++ b/sections/wiki/add_alias.php @@ -0,0 +1,19 @@ + edit +if(!is_number($_POST['article']) || $_POST['article'] == ''){ error(0); } + +$ArticleID = $_POST['article']; +$NewAlias = $Alias->convert($_POST['alias']); +$Dupe = $Alias->to_id($_POST['alias']); + +if($NewAlias!='' && $NewAlias!='addalias' && !$Dupe){ //Not null, and not dupe + $DB->query("INSERT INTO wiki_aliases (Alias, UserID, ArticleID) VALUES ('$NewAlias', '$LoggedUser[ID]', '$ArticleID')"); + $Alias->flush(); +} else { + error('The alias you attempted to add was either null or already in the database.'); +} + +$Cache->delete_value('wiki_article_'.$ArticleID); +header('Location: wiki.php?action=article&id='.$ArticleID); diff --git a/sections/wiki/aliases.php b/sections/wiki/aliases.php new file mode 100644 index 00000000..55bdee18 --- /dev/null +++ b/sections/wiki/aliases.php @@ -0,0 +1,58 @@ +article($ArticleID); +list($Revision, $Title, $Body, $Read, $Edit, $Date, $AuthorID, $AuthorName) = array_shift($Latest); +if($Edit > $LoggedUser['Class']){ error(404); } + +show_header($Title." Aliases"); +?> +

    Aliases

    + +
    +
    + + + + + + + + + +
    Add an alias to this article
    + + + +
    +
    + + + + + + + + + + +query("SELECT Alias FROM wiki_aliases WHERE ArticleID='$ArticleID'"); +while(list($Revision, $Title, $AuthorID, $AuthorName, $Date) = $DB->next_record()) { ?> + + + + + + + + +
    AliasRemove
    + +
    +
    +
    + diff --git a/sections/wiki/article.php b/sections/wiki/article.php new file mode 100644 index 00000000..1c3458f3 --- /dev/null +++ b/sections/wiki/article.php @@ -0,0 +1,131 @@ +to_id($_GET['name']); +} else { //No ID, No Name + //error(404); + error('Unknown article ['.display_str($_GET['id']).']'); +} + +if(!$ArticleID) { //No article found + show_header('No article found'); +?> +
    +

    No article found

    +
    + There is no article matching the name you requested. +
      +
    • Search for an article similar to this.
    • +
    • Link this to an existing article.
    • +
    • Create an article in its place.
    • +
    +
    +
    +article($ArticleID); +list($Revision, $Title, $Body, $Read, $Edit, $Date, $AuthorID, $AuthorName, $Aliases, $UserIDs) = array_shift($Article); +if($Read > $LoggedUser['Class']){ error(404); } + +show_header($Title,'wiki,bbcode'); +?> +
    +

    + +
    + +
    +
    +
    full_format($Body)?>
    +
    +
    +
    + diff --git a/sections/wiki/compare.php b/sections/wiki/compare.php new file mode 100644 index 00000000..6251b6d2 --- /dev/null +++ b/sections/wiki/compare.php @@ -0,0 +1,94 @@ + $OldString) { + $Key = $OldLine + $LineOffset; + if($Key<0) { $Key = 0; } + $Found = -1; + + while($Key
    '; + $LineOffset = $LineOffset - 1; + } elseif ($Found ==$OldLine+$LineOffset) { + $Result[] = '↕ '.$OldString.'
    '; + } elseif ($Found != $OldLine+$LineOffset) { + if ($Found < $OldLine+$LineOffset) { + $Result[] = '⇤ '.$OldString.'
    '; + } else { + $Result[] = '← '.$OldString.'
    '; + $Key = $OldLine + $LineOffset; + while ($Key<$Found) { + $Result[] = '→ '.$LineArrayNew[$Key].'
    '; + $Key++; + } + $Result[] = '→ '.$OldString.'
    '; + } + $LineOffset = $Found-$OldLine; + } + } + if(count($LineArrayNew)>count($LineArrayOld) + $LineOffset) { + $Key = count($LineArrayOld) + $LineOffset; + while($Key
    '; + $Key++; + } + } + return $Result; + +} + +function get_body($ID, $Rev) { + global $DB, $Revision, $Body; + if($Rev == $Revision) { + $Str = $Body; + } else { + $DB->query("SELECT Body FROM wiki_revisions WHERE ID='$ID' AND Revision='$Rev'"); + if(!$DB->record_count()) { error(404); } + list($Str) = $DB->next_record(); + } + return $Str; +} + +if ( + !isset($_GET['old']) || + !isset($_GET['new']) || + !isset($_GET['id']) || + !is_number($_GET['old']) || + !is_number($_GET['new']) || + !is_number($_GET['id']) || + $_GET['old'] > $_GET['new'] +) { error(0); } + +$ArticleID = $_GET['id']; + +$Article = $Alias->article($ArticleID); +list($Revision, $Title, $Body, $Read, $Edit, $Date, $AuthorID, $AuthorName) = array_shift($Article); +if($Read > $LoggedUser['Class']){ error(404); } + +show_header('Compare Article Revisions'); +$Diff2 = get_body($ArticleID, $_GET['new']); +$Diff1 = get_body($ArticleID, $_GET['old']); +?> +
    +

    Compare Revisions

    +
    +
    +
    +
    + diff --git a/sections/wiki/create.php b/sections/wiki/create.php new file mode 100644 index 00000000..a198829e --- /dev/null +++ b/sections/wiki/create.php @@ -0,0 +1,34 @@ + +
    +
    +
    + + +
    +

    Title

    + + + + +

    Alias

    +

    An exact search string or name that should lead to this article. (More can be added later)

    + + +

    Body

    + + +

    Access

    +

    There are some situations in which the viewing or editing of an article should be restricted to a certain class.

    + Restrict Read: + Restrict Edit: + +
    + +
    +
    +
    +
    +
    + diff --git a/sections/wiki/delete.php b/sections/wiki/delete.php new file mode 100644 index 00000000..ee48222f --- /dev/null +++ b/sections/wiki/delete.php @@ -0,0 +1,24 @@ +query("SELECT Title FROM wiki_articles WHERE ID = $ID"); + +if($DB->record_count() < 1) { + error(404); +} + +list($Title) = $DB->next_record(); +//Log +write_log("Wiki article ".$ID." (".$Title.") was deleted by ".$LoggedUser['Username']); +//Delete +$DB->query("DELETE FROM wiki_articles WHERE ID = $ID"); +$DB->query("DELETE FROM wiki_aliases WHERE ArticleID = $ID"); +$DB->query("DELETE FROM wiki_revisions WHERE ID = $ID"); + +$Cache->delete_value('wiki_article_'.$ID); +header("location: wiki.php"); + +?> diff --git a/sections/wiki/delete_alias.php b/sections/wiki/delete_alias.php new file mode 100644 index 00000000..d6b50fe9 --- /dev/null +++ b/sections/wiki/delete_alias.php @@ -0,0 +1,6 @@ +query("DELETE FROM wiki_aliases WHERE Alias='".$Alias->convert($_GET['alias'])."'"); +$Cache->delete_value('wiki_article_'.$Alias->to_id($_GET['alias'])); +$Alias->flush(); +?> diff --git a/sections/wiki/edit.php b/sections/wiki/edit.php new file mode 100644 index 00000000..d92a1bdf --- /dev/null +++ b/sections/wiki/edit.php @@ -0,0 +1,38 @@ +article($ArticleID); +list($Revision, $Title, $Body, $Read, $Edit, $Date, $Author) = array_shift($Article); +if($Edit > $LoggedUser['Class']){ + error('You do not have access to edit this article.'); +} + +show_header('Edit '.$Title); +?> +
    +
    +
    + + + + +
    +

    Title

    + +

    Body

    + + +

    Access

    +

    There are some situations in which the viewing or editing of an article should be restricted to a certain class.

    + Restrict Read: + Restrict Edit: + +
    + +
    +
    +
    +
    +
    + diff --git a/sections/wiki/index.php b/sections/wiki/index.php new file mode 100644 index 00000000..9f148355 --- /dev/null +++ b/sections/wiki/index.php @@ -0,0 +1,88 @@ + $Class) { + if($Class['Level'] <= $LoggedUser['Class']){ + $Return.='