// ==UserScript==
// @name Airdates.tv enhancer
// @namespace V@no
// @author V@no
// @description 2.5 tons of enhancements
// @include http://www.airdates.tv/*
// @include https://www.airdates.tv/*
// @include /^https?:\/\/(www\.)?disqus(cdn)?\.com\/embed\/comments\/.*$/
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAADv0lEQVRYw+1Wv08jVxD+Zt7uWy92jOMjh6ULBUkHVbiU5A9If6LKSUdqUNLQsnIKlC7FgZQmoqFCgvQoQog0F0EXqNOQAsjZHBL22t43k8K7iw25S5OcpeRGGu3b3TfvzXzzE3hHIybKFlEU0dzc3Henp6flOI4BQI0xaozRTqfDzjl4nqciAlWlJEkAAKqKIAhgjFEAYGaoqhLlR7PneVQqlZiZsbS09GxQAe+OMp8BmEjfBYCmzOk3HdhLA7I68A931pyyeSMUURTx4uJisrOzo+041nYca6/3jTpH6hypOig5lzM7KDtWdqyLPyyqI5ezAOqI1BEpSJXhlOH0yZOfdX19/ep1CMA5B1UFp/AREZhvjdEciMxESeEgsPKQQaSaYyWpnO/be4bnUvV6XYwxYGa8TRq6LQ2w0SlQrVYRhuHoFEjTaXQKtFot9Hq9f+0yEfdmBay1o0Vg5EGYJAlE5L+LgHP3jXu7VefvEMhK8cgUYGYMtNF/nMQlr1cgiiLudDpYXVUEgUUQWJTfKyIMawjDGqgICN8yjQG1sIZaWMOPv1bBgpwL1QcoTE6iMDkJFUC1C9Uuvvr6Prp5N5ydnaWzs7MhFygI4+P999gA1BoQrPhQSXsiC3QAuPehQwNBt9t/Jsn9IMzFtre3w/39/Yubm5tis9mEiFAQBP1NRNA+IeuYxhhYazX9RwAQx3GWyuR5HlQ1iysNggDT09OYmpq6vry8fFCv190QAvPz89/u7u6WDg4OUCgU0Gw2USqVAACFQgHn5+dERDDG5LVCREhEEAQBrLVoNpuoVqsQEVhr0Wg0wMwolUqkqri6ukIQBOOVSqUI4DpH4OTkxK6urnaOjo4A3GZDt9uFqkJEUC6X+25RharC932ICJxzeQHzfR/WWlhr0Wq1QEQgIvi+D1VFkiRoNBpYXl52a2trHgDQ8fGxv7m5+dvFxcWjDLJMiawwZQd5ngdjDB4//gSe56NcLsMYg3a7jRcvfkGxWAQR5QiFYQjf9zN3YWxsDBMTEyiXy2DmYGFhoevNzMx82m63HxWLxSELkyTpj2fphJT5HwDirgMnirjzEsQMZsL0Rx/j+tVVNhUPp7MCKn3jer0ekiQBEXWiKDLe1tYW7e3t5RGZWZtxKp8e1I/uw8PDv8hyxcOuwv/8FX7/qZLLqQjCKUHhYQ9/fPAlkufPoalLv3j6tB8DKysrz+I4/rA/zlN2nzAzRCRH4U6jYmRTKcBEpESk2X4RGSpyaaZk3xJV/X5jY+Ml3tH/nv4E5KQFif7uYoAAAAAASUVORK5CYII=
// @license MIT
// @version 1.73b5
// @run-at document-start
// @grant none
// @downloadURL https://update.greasyfork.cloud/scripts/28787/Airdatestv%20enhancer.user.js
// @updateURL https://update.greasyfork.cloud/scripts/28787/Airdatestv%20enhancer.meta.js
// ==/UserScript==
//tab = 2 spaces
/*global DB, GM_info, DISQUS, device, Colors, assignColor, loadColor, engines, ymToday, ym2str, coalesce, markSearchResults, search, updateSelectedOnly, readCookieRaw, loadArchiveFromPathname, hashChanged, require, HTMLDocument*/
/*jshint supernew: true, globals: true, evil: true, loopfunc: true, jquery: true, boss: true, expr: true, devel: true, strict: global, scripturl: true, -W018, -W014*/
"use strict";
var changesLogText = multiline(function(){/*
if all your settings are lost after website upgrade to secure connection on Oct 13, 2019,go to this page and backup your settings, then you can restore them in options
1.73b5 (2021-10-08)
+ restrict maximum width of the content (helps for wide resolution monitors)
! "collapse multiple" would collapse "premiere" or "returning" shows if there is an episode without season before it
! clicking on search link at the header would show arrow pointing at the searchbar without animation until page refreshed.
* clean up for jslint
//enableEpDateFixMenu
1.73b4 (2021-07-25)
+ setting to activate date offset
+ date offset of displays in tooltip which episode it's inherit current position
+ filter in changes log by clicking at legend titles
+ archive date to website title
! disqus reload button didn't scroll down properly
! disqus message count didn't work
! disqus theme didn't change together with main site
! opened details would get closed when "today" is changed
! date offset + time offset = incorrect date offset position
! errors on "_u" pages
* changes log will not longer popup when script first installed or when localStorage data deleted
* legend in changes log is always visible
- ability enable/disable episode offset feature via #epdatefix0 and #epdatefix1 hashtags
- disqus recommendations b.s.
? date offset + collapsemulti = hidden/incorrect title
1.73b3 (2020-12-13)
+ hide "Also on" section of disqus
1.73b2 (2020-10-15)
+ ability set date offset for episodes
! wrong svg icons color on light background
1.72.2 (2020-10-10)
! watched filter didn't work properly when show highlighted by search or marked as new/returned
1.72.1 (2020-10-10)
* tooltip on watched checkboxes now show additional info if SHIFT+click available
1.72 (2020-10-10)
+ while "Show all episodes" list is opened, holding SHIFT key and clicking on "watched" checkbox will select/deselect all previous episodes
+ filter to hide watched episodes
! duplicate week days for custom shows were not removed and not in order
! in some browsers (Tor Browser) after clicking left mouse button on a link that opens link in a new tab it would delete some of the user settings (that was some WTF bug)
1.71 (2020-06-26)
+ new option "number of opisodes per day" for custom shows
! menu popup did not change size with page zoom
1.70.1 (2020-05-13)
! links incorrectly selected for middle click in some cases
! watched incorrectly set on shows with changed "Episode # offset"
1.70 (2020-05-08)
+ date of content's last update at the bottom of the page
* table min width decreased to allow display without scrollbars on low resolution screens
! old unused settings were not deleted
! messages under search bar displayed in one line
! custom links not properly sorted
1.69 (2020-03-18)
* option "Sunday is first day of the week" changed to "First day of the week" with ability select Monday, Sunday or Saturday.
! missing days in the past in some situations
1.68 (2020-03-13)
+ option "Sunday is first day of the week"
! some show's name incorrectly truncated in links in the search result
1.67 (2020-02-02)
+ ability change some colors of the website
+ ability enter RGB and HSB values in colorpicker
! accounts with hundreds "my shows" could fail properly sort shows
! colorpicker not shown in Custom Shows settings
1.66.1 (2020-01-14)
! option's misalignment in default theme
* color picker for today's color now shows the color value in option's field
1.66 (2020-01-14)
+ option for today's color
1.65.2 (2020-01-12)
! error when trying open an item when searched for info:myshows
* today's color in dark theme to orange
1.65.1 (2020-01-12)
! account popup would show up after closing secondary popup via X icon (options, custom shows, etc)
! my shows on top shown in wrong ordered
* improved my show on top sorting performance
1.65 (2020-01-1)
+ option to show "My Shows" on top of the list
1.64.1 (2020-01-06)
! middle click on a show would not open selected links
1.64 (2020-01-04)
+ new tags for custom links: {YEAR}, {MONTH}, {DAY}
1.63.2 (2020-01-04)
* it's possible now add custom show without specifying season
1.63.1 (2020-01-04)
! custom shows with day of the week would not set correct date with time offset activated
* horizontal scrollbar shown in Custom Shows popup
1.63 (2020-01-03)
+ prompt's buttons now highlighted when cursor over
+ option to make popups more stand out by bluring background around them
+ ability specify day of the week of a custom show
! horizontal scrollbar shown in Links Manager
! account popup not dimmed when import/export colors prompt opened
* when popups are opened, page scroll is disabled
1.62.2 (2019-10-24)
! fixed missing weeks
1.62.1 (2019-10-24)
+ tooltip for "go to the top" button
! leave archive bottom link was not scroll to the top
1.62 (2019-10-24)
+ jump to the top button
+ option to show next/prev month buttons under calendar
! some color issue in changes log with dark theme
! prompt to enter a date to jump to (when clicked on archive's date) was not showing correct currently viewing date
1.61.2 (2019-10-20)
+ information about server upgrade inside changes log and what to do
1.61.1 (2019-10-13)
+ #backupsettings to the link under search bar
! link in disqus comments to non-secure website with a hashtag command would execute command instead of opening webpage
1.61 (2019-10-13)
+ added hashtag command #backupsettings
1.60.4 (2019-10-13)
+ tooltip explaining how user's colors saved
! links favicons used insecured connection
1.60.3 (2019-07-14)
+ main menu icon instead of "Account" link
! Sunday column would wrap under Saturday in small windows
* cookies icon for guests
1.60.2 (2019-07-14)
+ search icons
! cookies that store guest's colors will no longer expire
* search bar placeholder to "Find Show ..."
* text "Account" to "Tools" on main menu link
1.60.1 (2019-03-31)
! watched checkbox was removed from first custom show of the week when new day started
1.60 (2019-03-04)
+ ADEU keyword in disqus
! disqus troll script would not initialize on new comments which were loaded without page refresh
* custom shows link no longer shown when viewing as another user
1.59 (2018-12-09)
+ ability add custom icon for each link (can be an URL or "data:" type)
+ option to change how custom colors displayed: use all available width or wrap in 7 per line
! some changes links manager would not reflect in opened details of a show
! improved drag'n drop in links manager
! greatly improved performance during changing number of custom colors to display in settings
* quick colors and link's icons are now scalable with page zoom in Waterfox
* replaced color picker icon with a SVG, which allows to be scaled without compromising quality
1.58.1 (2018-12-02)
! in some situations all days disappear
! search bar not centered
1.58 (2018-12-02)
+ ability change order in list of all episodes of a show
1.57 (2018-11-20)
+ after an update changes log highlights changes between new and old versions
! "My Shows" displayed duplicate entries when settings where restored from old backups
! deleted custom show has "edit" link in "My Shows" list, producing error in console
! newly added custom color wasn't pre-selected
1.56.1 (2018-11-18)
* selected color in quick color picks now shows rounded
1.56 (2018-11-18)
+ changes log shown after update (can be disabled via checkbox in top-right corner)
+ quick color picks shows which one is the current color
! after a link was changed, middle click on a show would use old data for the selected links
! links manager missing cursor-over indicator on edit/delete buttons
! custom show name field shown as "error" after "clear" button used
1.55.2 (2018-11-10)
! settings restore could create duplicate custom shows
! clicking on disqus notification icon would not open the notification panel
1.55.1 (2018-11-10)
! search by name failed find custom shows
* custom shows no longer displayed as duplicate if original show with exact same name + season + episode already exists in the same day
1.55 (2018-11-10)
+ tooltips on quick color pick
+ option to change displayed number of custom colors
+ when editing a custom show, if name changed to an existing show, the submit button label changes to "Merge", the name in the list changes color to red and the show it will be merged with changes to green
! color box of a last in the list custom show would display outside of the area, requiring user to scroll
! clicking edit link on custom show from search results would not highlight line in episodes data
! when colors box opened in custom shows popup, escape button closes the color box instead of whole custom shows popup
! clicking outside of color box in "Custom shows" could activate other actions on clicked element
* increased number of custom colors to remember from 7 to 100
* when color box in "Custom shows" list is opened, popup around of it fades and hovering cursor over other elements on the page no longer trigger anything
1.54.2 (2018-11-07)
! number of weeks ignored if number of past weeks changed immediately after number of weeks changed from "All" to any number
1.54.1 (2018-11-07)
! incorrect number of weeks shown in search results
1.54 (2018-11-07)
+ option to limit how many weeks to show (past weeks are included into the count)
* increased number of past weeks to 5
1.53.2 (2018-11-06)
! disqus trolls script didn't work
1.53.1 (2018-11-06)
! custom show's color box was displayed on it's own line in older browsers
1.53 (2018-11-06)
+ colors in custom shows list
+ clicking "Edit" on custom show from details dropdown automatically highlights the episode data line
! collapse multiple didn't work on added/updated shows without page refresh
! some icons in details dropdown were black on dark background
* if custom show name matches any existing custom shows, it automatically highlighted and currently selected one shows as crossed off (because it would be merged with the matched one)
* season/episode number is no longer restricted to max 99
1.52 (2018-11-05)
+ when editing a custom show and name changed to unique, it's now possible add it as a new show or update existing
+ "More info" state in custom show editor is now remembered
* any field that prevent custom show from submitting is now highlighted
1.51.1 (2018-11-05)
! custom shows not shown in past weeks
1.51 (2018-11-04)
+ new show episode data fields are now can be separated by any character(s) that is not 0-9, date also may be spited as separate year, month and day
+ visual aid in the custom shows list highlighting affected item after submitting data
+ more explanation about episode data format
+ Custom shows form changes label on submit button to reflect if a show being edited or a new show will be created
+ arrow keys in custom shows list would select for editing next/prev show
! text-shadow on titles highlighted by search would affect new/returning tags, producing unreadable text
! clicking "Show all episodes" from "My Shows" list would not properly display list of episodes
! missing "Edit" link in for custom shows in "My shows" list
! white icon in show's details in search results
* new show episodes data fields are now showing evenly spaced
1.50 (2018-11-03)
+ backup/restore custom shows
1.49 (2018-11-03)
+ if custom show fields are empty, deleting a show would fill up the fields with information from deleted show
1.48.1 (2018-11-03)
! myshow list would not update new name of custom shows
1.48 (2018-11-03)
+ ability add custom shows
+ text shadow on highlighted (rainbow) search results
! in some cases script totally failed, due to work around for SVG images showing too large while page is still loading.
1.47 (2018-10-19)
+ links regex now applied to the entire url, but only if MONKEY_REGEXP or MONKEY_N_REGEXP tags were not used
! MagnetDL links included unnecessary / at the end search keyword
1.46.2 (2018-10-19)
! horizontal scrollbar shown when links manager is overflowing
! submit button not disabled after new link was submitted
1.46.1 (2018-10-19)
! issues after a link was created and deleted without page refresh
1.46 (2018-10-18)
+ ability add regular expressions filters to links (one regexp per line)
! edit buttons not shown in links manager in some browsers
! edited link would fail in opened show details
! in older browsers show details would not open on first click and episode offset would fail
! MagnetDL links
1.45.3 (2018-10-02)
! track today not working when 1st of the month is Monday
1.45.2 (2018-09-29)
! missing comments reload button in some browsers
! black comments reload icon in dark theme
1.45.1 (2018-08-12)
! filter checkboxes were too close to each other
1.45 (2018-08-12)
+ clicking on logo changes theme
! JS errors at login page
* tweaked colors of day's date in dark theme
* changed theme handling/selection in options, this will allow user add custom themes in the future
1.44.2 (2018-07-19)
! loading icon when clicked at disqus notification badge would hide prematurely before notification window opened.
! disqus badge routine start multiple timers
1.44.1 (2018-07-15)
! dark theme looked bad in archive
* tweaked the look of notification badge
1.44 (2018-07-15)
+ disqus message notification badge on top of the page
+ colorpicker set to last used color if current show has no assigned color
1.43.1 (2018-07-14)
! colorpicker stops working if used at search results
! on small screens sundays would move underneath of saturday when search is active
! when myshows list is opened, adding/removing a show would not reflect at the list
1.43 (2018-07-14)
+ remember and show last 7 custom colors as quick pick, they can be removed via middle click
! main input hex color in colopicker would fail
* updated logo with less outline on darker theme
1.42 (2018-07-14)
+ updated logo, it now looks good with any background.
! disqus would not show text after switching theme without page refresh
1.41 (2018-07-13)
+ dark theme build-in
1.40.2 (2018-07-13)
* better support for dark themes
1.40.1 (2018-07-10)
! on small screens sundays would move underneath of saturday
* opened show border now obeys color of the text
1.40 (2018-07-09)
+ episode season number offset
1.39 (2018-07-09)
+ episode number offset
! script fails on some pages displaying huge characters (i.e. login page)
! in some browsers it shows huge "something" while page still loading
1.38.3 (2018-05-26)
! collapse multiple failed at midnight when enabled "Track today"
1.38.2 (2018-04-23)
! Show details would not open
1.38.1 (2018-04-22)
* clean up saved settings (remove any non-existing or with missmatched type settings)
1.38 (2018-04-16)
+ option to track today (feature introduced in v 1.35)
1.37.4 (2018-04-15)
! MS Edge compatibility
1.37.3 (2018-04-13)
! if episode is in the past and hidden via "show past weeks" setting, clicking on "Show in calendar" from search result would not reveal the episode.
* if getting name of same show failed, next attempt will be possible only after 1 hour
* if getting name of a show failed during period of 4 weeks, the show will be removed from the account.
1.37.2 (2018-03-27)
+ enter key now submits form in links manager
! left click on links didn't work
! links with empty URL field no longer accepted
* undo message after clear colors/hidde or watched list now visible even when page scrolled down
* when viewing as different user, links to clear colors/hidden and watched lists are no longer visible
* Add and Reset buttons in links manager renamed to Submit and Clear
1.37.1 (2018-03-25)
! broken my shows list in Firefox
* renamed "Show hidden" checkbox to "Hidden shows"
1.37 (2018-03-23)
+ reload disqus button
! clicking on engine's checkboxes would open the engine link
1.36.3 (2018-03-18)
! errors in console in MS Edge
1.36.2 (2018-03-18)
! in certain situations changing time offset would break collapse multiple
! auto scroll setting were inverted on page refresh
* settings "Scroll on search" renamed to "Auto scroll to the top"
1.36.1 (2018-03-18)
! in certain situations changing time offset would break collapse multiple
1.36 (2018-03-18)
+ links to Wikipedia in search result
+ information about shows stored in local storage, now included in settings backup
! 1.35 broke disqus
! links to airdates hashtags mistakenly opened in new tab if hashtag was was after domain name instead of /
! invalid colors would display show with white text
! searches that include info:A-Z no longer sent to server
! info:myshows didn't list shows without name
1.35 (2018-03-17)
+ today automatically changes at midnight without page refresh and updates listing of current month
! possible open multiple popups via hashtags
* back button now shows on popups opened via hashtag
1.34.1 (2018-03-15)
! search result had too much empty space on top
! link under search bar covers Sundays date when small logo enabled
* different approach stopping page from scrolling on search
1.34 (2018-03-15)
+ time offset option
+ option to disable scroll when using search field
1.33.1 (2018-03-12)
! color input field undo now records when color picked via palette
1.33 (2018-03-12)
+ missing color input field in color picker
* improved color input field in color picker: no need for # and it automatically filters out non-valid values, custom undo/redo that works between shows
1.32 (2018-03-04)
+ add/reset buttons in Links Manager are now disabled when fields are empty
+ clear colors/hidden/watched lists in options
+ ability undo after clear colors/hidden/watched
! reset button in Links Manager would not remove icon in result when clicked first time
! broken restore settings
! when a popup once opened via a hashtag (#options, #linksmanager, #changes), opening that popup via click would not show back button
* alert popup after clear colors/hidden/watched replaced with a notification message with ability to undo
1.31 (2018-02-25)
+ button in prompt popup to save/load file
+ hashtags #options and #linksmanager
+ tooltips on links in links manager
! color validation during import colors didn't work properly
! the end of text in url field in links manager was covered up by the dropdown menu button
! color picker in search result displayed behind the search results and was inaccessible
! asterisk on new links in links manager is now always visible even if link's title is truncated
* export colors filters out invalid colors
* links manager is now consistent width
- save/load from file links, they are now integrated into prompt itself
1.30.2 (2018-02-18)
! incorrect favicon for internal airdates.tv links
1.30.1 (2018-02-18)
! error opening show from "My shows" list
1.30 (2018-02-18)
+ animation speed setting
+ links manager automatically scrolls to new (or edited) link after submit
+ custom prompt popup for import/export colors/settings
! exporting ~160 colors via text string would corrupt some colors due to Chrome limitations
! errors in console when attempting restore settings or import colors with invalid data
* importing colors now validates input before saving to the account
1.29 (2018-02-12)
+ ESC key closes popups
+ show/hide this show icon
! when number of visible links different from default, opening a show would make the animation jump
! long text wrapped in popup windows
! clicking on edit link icon in Links Manager, would not display correct lin in the "Result" row
! "reset sort" link in Links Manager would take whole row
! MS Edge would not initialize properly
* links with long names are longer "wrap"
* significally improved performance of Links manager
* faster opening/closing show animation
* selectable links in show details are now separate from other links
* links manager popup now has limited max size
1.28.4 (2018-02-07)
+ random series as example in links manager
! editing/adding a link while a show opened would produce incorrect links in the opened show until page refresh
1.28.3 (2018-02-07)
! Firefox decided render shadow much bigger then supposed to
1.28.2 (2018-02-07)
! in Firefox shadow would show on opened show when popup was opened
1.28.1 (2018-02-07)
+ shadow on "popups", making them more pronounced
1.28 (2018-02-04)
+ search by adding #s:keyword in the address
+ changes log
+ ability use hash tags as links in comments (#s:search-keyword, #info:NN, #myshows, #hidden, #changes). Without ADE it will open a blank page.
+ option for small logo
! disqus troll would not work at all in some browsers
! disqus troll would not work on additionally loaded comments
! "watched" checkboxes shown through search field
! close button on popups would not work if cursor not in the middle of it
* removed disq.us from links in comments
* links in comments open in new tab
* when searching via hash tag, clearing search field with X icon would also remove the hash tag from address bar
1.27.5 (2018-01-22)
! broken fix for paste via right click in search bar
1.27.4 (2018-01-22)
+ cloud icon next to member name
1.27.3 (2018-01-22)
! fails initialize with some invalid colors in cookies
* replaced some icons with SVG, should now be more browser independent and consistent
1.27.2 (2018-01-21)
! sorting by color with fallback to sorting by name was in reverse
1.27 (2018-01-21)
+ link to support website
! middle click on title would attempt open 2 tabs for each selected link
! significantly improved initialization speed for guests and members with no colors (very noticeable with #showhidden in the address)
*/}, true).trim();
let log = console.log.bind(console),
self = this,
timeOffset = 0,
isFrame = window.top !== window.self,
_Date = Date,
today,
blankFunc = function(){},
SVG = {
del: '',
search: '',
show: '',
hide: '',
backup: '',
restore: '',
clear: '',
edit: '',
guest: '',
link: '',
customlinks: '',
customshows: '',
settings: '',
menu: '',
user: '',
reload: 'Reload',
close: '',
closehover: '',
viewas: '',
back: '',
};
/*work around for some SVG pictures shown huge before page is fully loaded*/
(function loop()
{
let head = document.head;
if (!head)
{
return setTimeout(loop, 0);
}
let style = document.createElement("style");
head.appendChild(style);
style.innerHTML = "svg{max-width:1.2em;max-height:1.2em;}";
if (!isFrame && window.location.href.match(/^http:/))
{
let s = document.createElement("script");
s.src = "/public/javascripts/db.js";
head.appendChild(s);
s = document.createElement("script");
s.src = "/public/javascripts/main.js";
head.appendChild(s);
s = document.createElement("script");
s.src = "/public/javascripts/jqColorPicker.min.js";
head.appendChild(s);
window.engines = [];
}
})();
receiveMessage.f = {};//list of functions
receiveMessage.f.reloadDisqus = function messageFunc_reloadDisqus(r)
{
if (typeof(r) == "undefined")
{
this.r = true;
DISQUS.reset({
reload: true,
});
}
else if (this.r)
{
$("html, body").animate({scrollTop: $("#disqus_thread").find("iframe")[0].offsetTop + r }, 300);
}
};
window.self.addEventListener("message", receiveMessage, false);
if (!isFrame)
{
try
{
timeOffset = ~~ls("settings").timeOffset;
if (!(timeOffset instanceof Number))
timeOffset = 0;
}
catch(er){}
Date = function()
{
let args = Array.prototype.slice.call(arguments);
args.splice(0, 0, this);
let n = (new (Function.prototype.bind.apply(_Date, args))).getTime() + 3600000 * timeOffset;
return new _Date(n);
};
Date._now = function()
{
return (new _Date()).getTime();
// return Math.floor((Date.now() - 1523246400000) / 1000); //2018-04-09 00:00:00
};
}
if (!Date.now)
{
Date.now = function()
{
return (new Date()).getTime();
};
}
Object.defineProperty(window, 'browser', { get: function()
{
let browser = "";
if((navigator.userAgent.indexOf("Opera") || navigator.userAgent.indexOf('OPR')) != -1 )
{
browser = "opera";
}
else if(navigator.userAgent.indexOf("Edge") != -1)
{
browser = "edge";
}
else if(navigator.userAgent.indexOf("Chrome") != -1 )
{
browser = "chrome";
}
else if(navigator.userAgent.indexOf("Firefox") != -1 )
{
browser = "ff";
}
else if(navigator.userAgent.indexOf("Safari") != -1)
{
browser = "safari";
}
else if((navigator.userAgent.indexOf("MSIE") != -1 ) || (!!document.documentMode == true )) //IF IE > 10
{
browser = "ie";
}
return browser;
}});
let mainFunc = function mainFunc(event)
{
/* jshint validthis: true */
if (typeof($) == "undefined")
return;
//create a DIV container and move everything into that container
const elContent = document.getElementById("content") || document.createElement("div"),
elSearchbarContainer = document.createElement("div");
elContent.id = "content";
elSearchbarContainer.id = "searchbarContainer";
elSearchbarContainer.appendChild(document.getElementById("searchbar"));
elContent.appendChild(elSearchbarContainer);
while(document.body.children.length)
elContent.appendChild(document.body.firstChild);
document.body.appendChild(elContent);
let browser = window.browser;
if (browser)
document.body.classList.toggle(browser, true);
let disqusMessageCount = function disqusMessageCount(count)
{
if (count)
{
disqusMessageCount.el.setAttribute("unread", "");
disqusMessageNotifLoaded(false);
}
else
{
disqusMessageCount.el.removeAttribute("unread");
// disqusMessageCount.el.classList.toggle("loading", false);
disqusMessageNotifLoaded(false);
count = "";
}
disqusMessageCount.el.textContent = count;
};
receiveMessage.f.disqusMessageCount = disqusMessageCount;
let adeName = "Airdates.tv enhancer",
adeVersion = "n/a",
prevVersion = null,
force = false,
enginesDefault = [],
_engines = [],
_hidden = ls("hidden") || [],
loopWait = 1000,
_enginesList = [],
pickerCallbacks = {};
try
{
adeName = GM_info.script.name;
adeVersion = GM_info.script.version;
}catch(er){}
cs.list = ["s","n"];
cs.listLegacy = {
sh: "showHidden",
sn: "showNew",
sr: "showReturn",
cm: "collapseMulti",
w: "weeksPast",
wa: "enableWatched",
middleClick: "middleClick"
};
let enginesHide = ls("enginesHide") || [];
let Settings = {
SORT_NAME: 0,
SORT_COLOR: 1,
inited: false,
box: null,
/*
colorsDef: {
"807fff": {name: ""},
"ff7fff": {name: ""},
"80ff7f": {name: ""},
"7fffff": {name: ""},
"ff7f7f": {name: ""},
},
*/
prefs: {},
prefsDef: {
animSpeed: 2,
archiveBottom: 1, //show next/prev month links below calendar
collapseMulti: 0,
cushowsHelp: 0,
enableWatched: 0,
enableEpDateFix: 0,
lastColor: "",
lastColors: [],
lastColorsLine: 7, //number of last colors per line
lastColorsShow: 7, //number of last colors to show
middleClick: [],
myShowsTop: 0, //move my shows on top of the list
noChangesLog: 0,
popupBlur: 1, //blur background when popups are shown
searchOrder: 0,
searchScroll: 1,
shortTitle: 0,
shortTitleExpand: 1,
showHidden: 0,
showNew: 0,
showReturn: 0,
showWatched: 1,
smallLogo: 0,
sortBy: 0,
theme: "",
themeColors: {
text: "",
bg: "",
date: "",
dateBg: "",
today: "",
todayBg: "",
todayBorder: ""
},
timeOffset: 0,
todayChange: 1,
version: "",
weeks: 0, //total number of weeks to show
weeksPast: 0, //number of past weeks
weekStart: 0, //0=Mon, 1=Sun, 2=Sat
},
prefsFilter: {
animSpeed: function(p)
{
return Math.max(0, Math.min(9, p));
},
},
filter: function Settings_filter(id, val)
{
if (id in this.prefsFilter)
return this.prefsFilter[id](val);
return val;
},
pref: function Settings_pref(id, val, prefs)
{
prefs = prefs || this.prefs;
let ids = id.split(".");
if (ids.length > 1)
{
return this.pref(ids[1], val, prefs[ids[0]]);
}
if (typeof(val) == "undefined")
return typeof(prefs[id]) == "undefined" ? null : prefs[id];
prefs[id] = this.filter(id, val);
this.save();
},
init: function Settings_init()
{
if (this.inited)
return;
this.prefs = ls("settings");
if (!this.prefs || typeof(this.prefs) != "object")
this.prefs = cloneObj(this.prefsDef);
if ("weeks" in this.prefs && !("weeksPast" in this.prefs))
{
this.prefs.weeksPast = this.prefs.weeks;
this.prefs.weeks = this.prefsDef.weeks;
}
//add any missing settings and remove any non-existing
function fixPref(pref, def)
{
for(let i in def)
{
if (!(i in pref))
pref[i] = def[i];
if (typeof(def[i]) == "object" && !Array.isArray(def[i]))
fixPref(pref[i], def[i]);
}
for(let i in pref)
{
if (!(i in def))
delete pref[i];
}
}
fixPref(this.prefs, this.prefsDef);
if (this.prefs.theme === 1)
this.prefs.theme = "dark";
//remove any non-existing settings
for(let i in this.prefs)
{
if (!(i in this.prefsDef) || typeof(this.prefs[i]) !== typeof(this.prefsDef[i]))
delete this.prefs[i];
}
let c,// = cs("wa"),
s = false;
/*
//too old compatibility to care?
if (c !== null)
{
this.prefs.enableWatched = c ? 1 : 0;
eraseCookie("wa");
s = true;
}
c = cs("showhidden");
if (c !== null)
{
this.prefs.showHidden = c ? 1 : 0;
eraseCookie("showhidden");
s = true;
}
c = cs("sh");
if (c !== null)
{
this.prefs.showHidden = c ? 1 : 0;
eraseCookie("sh");
s = true;
}
c = cs("cm");
if (c !== null)
{
this.prefs.collapseMulti = c ? 1 : 0;
eraseCookie("cm");
s = true;
}
c = cs("middleClick");
if (c !== null)
{
this.prefs.middleClick = c ? c : [];
eraseCookie("middleClick");
s = true;
}
c = cs("w");
if (c !== null)
{
this.prefs.weeks = c;
eraseCookie("w");
s = true;
}
*/
/* splitting New/Returning into two separate filters */
c = cs("sn");
if (c === null && this.pref("showNew") === null)
{
let n = cs("n") ? 1 : 0;
this.prefs.showNew = n;
this.prefs.showReturn = n;
s = true;
}
else if (c !== null)
{
this.prefs.showNew = c;
eraseCookie("sn");
s = true;
}
c = cs("sr");
if (c !== null)
{
this.prefs.showReturn = c;
eraseCookie("sr");
s = true;
}
window.createCookie = createCookie;
// window.eraseCookie = eraseCookie;
// window.readCookie = readCookie;
if (this.pref("version") != adeVersion)
{
if (!Settings.prefs.noChangesLog && Settings.prefs.version != adeVersion)
{
prevVersion = Settings.prefs.version;
if (Settings.prefs.version !== "")
{
setTimeout(function()
{
changesLog.show(true);
});
}
if (!DB.loggedInUsername)
{
setTimeout(function()
{
for(let id in DB.savedColors)
{
DB.setColor(id, DB.savedColors[id]);
}
});
}
}
if ("weekSunday" in this.prefs)
{
this.prefs.weekStart = this.prefs.weekSunday;
delete this.prefs.weekSunday;
this.save();
}
if (versionsCompare(this.pref("version"), "1.71") < 0)
{
let l = ls("customShows") || {i:1,l:{}},
changed = false;
for (let obj in l.l)
{
for (let i = 0; i < l.l[obj][1].length; i++)
{
let data = l.l[obj][1][i];
if (data.length == 6)
{
data[6] = data[5]; //custom show days of the week
data[5] = 1;
changed = true;
}
}
}
if (changed)
{
ls("customShows", l);
}
}
if (versionsCompare(this.pref("version"), "1.72") < 0)
{
let w = watched._list;
for (let i in w)
{
let l = w[i],
n = [];
for (let e = 0; e < l.length; e++)
{
n[n.length] = episodeTools.short(l[e]);
}
w[i] = n;
}
watched.save(1);
}
this.prefs.version = adeVersion;
s = true;
}
if (s)
this.save();
this.themes.init();
this.create();
this.lastUpdateShow();
this.inited = true;
},//Settings.init()
create: function Settings_create(callback)
{
if (Settings.box)
return callback ? callback() : true;
let html = multiline(function(){/*
{SVG-BACK}
Options
{SVG-CLOSEHOVER}
{SVG-CLOSE}
*/});//html
let popup = $(html).appendTo("#content"),
content = popup.find(".content"),
a = document.createElement("a"),
i = document.createElement("span"),
span = document.createElement("div"),
that = self,
opt;
span.appendChild(i);
span.appendChild(a);
Settings.box = popup;
content.append(createCheckbox("enableWatched", "Enable watched", this.prefs.enableWatched ? true : false, this.callback, null, ""));
//enableEpDateFixMenu
content.append(createCheckbox("enableEpDateFix", "Enable Episode Date Offset", this.prefs.enableEpDateFix ? true : false, function(e, id, check)
{
epDateFix.init(check);
}, ['Warning! This will increase page loading time.\n\nRequires page reload'], ""));
content.append(createCheckbox("shortTitle", "Truncate long titles", this.prefs.shortTitle ? true : false, this.callback, ["Shorten titles to fit into single row."], ""));
content.append(createCheckbox("shortTitleExpand", "Auto expand truncated titles", this.prefs.shortTitleExpand ? true : false, this.callback, ["Show full title when cursor over it. If disabled you still be able see full title in tooltip or when show is opened."], ""));
content.append(createCheckbox("smallLogo", "Small logo", this.prefs.smallLogo ? true : false, this.callback, null, ""));
content.append(createCheckbox("searchScroll", "Auto scroll to the top", this.prefs.searchScroll ? true : false, this.callback, ["Scroll to the top on search and page refresh"], ""));
content.append(createCheckbox("todayChange", "Track today", this.prefs.todayChange ? true : false, this.callback, ['Automatically change "today" at midnight'], ""));
content.append(createCheckbox("archiveBottom", "Show bottom archive links", this.prefs.archiveBottom ? true : false, this.callback, ['Show next/prev month links below calendar'], ""));
content.append(createCheckbox("popupBlur", "Blur behind popups", this.prefs.popupBlur ? true : false, this.callback, ['Make popups standout more'], ""));
content.append(createCheckbox("myShowsTop", "My Shows on top", this.prefs.myShowsTop ? true : false, function(e, id, check)
{
that.callback(e, id, check);
sortMyShows();
}, ['Move My Shows to the top of the list'], ""));
opt = $(multiline(function(){/*
First day of the week:
*/}))
.appendTo(content)
.find("select")
.val(Settings.pref("weekStart"))
.on("input", function(evt)
{
Settings.pref("weekStart", ~~this.value);
if (!evt.isTrigger)
pastLoaded();
})
.trigger("input");
opt = $(multiline(function(){/*
Show number of weeks:
*/}))
.appendTo(content)
.find("#weeks")
.val(Settings.pref("weeks"))
.on("input", function(evt)
{
// this.nextSibling.textContent = " week" + ((this.value == 1) ? "" : "s");
Settings.pref("weeks", ~~this.value);
if (!evt.isTrigger)
pastLoaded();
})
.trigger("input");
opt = $(multiline(function(){/*
Show last custom colors
*/}))
.appendTo(content)
.find("input")
.val(Settings.pref("lastColorsShow"))
.attr("max", Settings.colors.max)
.on("input", function(evt)
{
this.nextSibling.textContent = " last custom color" + ((this.value == 1) ? "" : "s");
let s = this.selectionStart,
e = this.selectionEnd,
val = Math.min(Settings.colors.max, Math.max(0, ~~this.value.replace(/[^0-9\-]/g, "")));
this.value = val;
if (e !== null)
this.selectionEnd = e;
if (s !== null)
this.selectionStart = s;
Settings.pref("lastColorsShow", val);
if (!evt.isTrigger)
{
clearTimeout(opt.timer);
opt.timer = setTimeout(Settings.colors.init, 100);
}
})
.trigger("input");
content.append(createCheckbox("lastColorsLine", "Custom colors fill width", this.prefs.lastColorsLine ? false : true, function(e, id, check)
{
let num = check ? 0 : 7;
Settings.pref("lastColorsLine", num);
if (!e.isTrigger)
Settings.colors.init();
}, ['Use all available width, or show 7 custOm colors per line'], ""));
opt = $(multiline(function(){/*
Time offset: hours
*/}))
.appendTo(content)
.find("#timeOffset")
.val(Settings.pref("timeOffset"))
.on("input", function(evt)
{
this.nextSibling.textContent = " hour" + ((this.value == 1) ? "" : "s");
let s = this.selectionStart,
e = this.selectionEnd;
timeOffset = Math.min(24, Math.max(-24, Number(this.value.replace(/[^0-9\-]/g, ""))));
this.value = timeOffset;
if (e !== null)
this.selectionEnd = e;
if (s !== null)
this.selectionStart = s;
Settings.pref("timeOffset", timeOffset);
if (!evt.isTrigger)
todayChange(timeOffset);
})
.trigger("input");
if (!device.tablet() && !device.mobile())
{
opt = $(multiline(function(){/*
Animation speed
12345678910
*/}))
.appendTo(content)
.find("#animSpeed")
.val(10-Settings.pref("animSpeed"))
.on("input", function(e)
{
Settings.pref("animSpeed", 10-Number(this.value));
$("#animSpeedVal").text(this.value);
})
.trigger("input");
}
opt = $(multiline(function(){/*
Theme:
*/}))
.appendTo(content)
.find("select")
.each(function(i, el)
{
let option = document.createElement("option");
for(let id in Settings.themes.list)
{
option = option.cloneNode(false);
option.value = id;
let name = id;
if ("name" in Settings.themes.list[name])
name = Settings.themes.list[name].name;
if (name === "")
name = "Default";
option.innerHTML = name;
el.appendChild(option);
}
el.value = Settings.prefs.theme;
})
.on("change", function(evt)
{
Settings.themes.load(evt.target.value);
})
.trigger("change");
let box = $(''),
info = Settings.themes.quickOverrideTempl,
samples = {},
sampleGroup = 0;
let templ = multiline(function(){/*
{SVG-DEL}
*/});
for(let i in Settings.prefsDef.themeColors)
{
opt = $(templ
.replace(/\{ID\}/g, i)
.replace(/\{LABEL\}/g, info[i].label || "")
.replace(/\{TITLE\}/g, info[i].title || ""))
.appendTo(box)
.find(".color")
.each(function()
{
let that = this,
name = i,
data = {};
data[name] = Settings.pref("themeColors." + name);
Settings.themes.quickOverride(data);
if (data[name])
that.parentNode.setAttribute("color", data[name]);
else
that.parentNode.removeAttribute("color");
pickerCallbacks["themeColor_" + name] = function(val, temp)
{
let c = (typeof(val) == "boolean") ? val : temp ? true :false;
that.parentNode.classList.toggle("colorpicker", c);
that.parentNode.parentNode.classList.toggle("colorpicker", c);
let b = document.getElementById("themeColorBox_" + that.parentNode._example),
s = b.getElementsByClassName("example")[0];
if (c)
b.setAttribute("down", that.parentNode._down);
else
b.removeAttribute("down");
if (typeof(val) == "boolean")
val = null;
if (!temp)
{
if (val)
that.parentNode.setAttribute("color", val);
else
that.parentNode.removeAttribute("color");
Settings.pref("themeColors." + name, val);
}
if (val === null)
{
val = Settings.prefs.themeColors[name];
}
let data = {};
data[name] = val;
Settings.themes.quickOverride(data);
};
})
.parent()
.find(".del")
.on("click", function()
{
pickerCallbacks["themeColor_" + i]("");
});
if (info[i].sample)
{
let p = opt.parent();
let s = info[i].sample.split(",");
for(let i = 0; i < s.length; i++)
{
if (typeof(samples[s[i]]) == "undefined")
samples[s[i]] = [0, sampleGroup++];
samples[s[i]][0]++;
p[0]._down = samples[s[i]][0];
p[0].classList.toggle("group" + (samples[s[i]][1] % 2), true);
}
p[0]._example = info[i].sample;
}
}
box.appendTo(content);
for (let s in samples)
{
let b = $("#themeColorBox_" + s);
if (b.prev().hasClass("themeColorBox"))
{
b.before('');
}
b.append($('Example'));
for(let i = 1; i < samples[s][0]; i++)
{
b = b.next();
b[0]._down = samples[s][0] - (samples[s][0] - ~~b[0]._down);
}
}
content.append('');
a.href = "#";
i.innerHTML = SVG.backup;
a.textContent = "Backup settings";
a.id = "settingsBackup";
span.title = "Backup all settings, including links manager data, watched and hidden shows lists, middle click selection, last custom colors and custom shows.";
a.addEventListener("click", function backupSettings_link_evtClick(e)
{
e.preventDefault();
Settings.backup();
return false;
}, false);
content.append(span);
span = span.cloneNode(true);
i = span.firstChild;
a = i.nextSibling;
a.id = "settingsRestore";
span.title = "Note, your current watched and hidden shows list will stay intact, new shows will be added to it.\nCustom links will only overwrite existing with matched ID.\nAll other settings will be overwritten";
i.innerHTML = SVG.restore;
a.textContent = "Restore settings";
function restore(str)
{
let reload = false,
txt = "Error restoring settings";
if(!str)
return;
let hiddenNum = 0,
watchedNum = 0,
settingsNum = 0,
enginesNum = 0,
engineHideNum = 0,
customShowsNum = 0,
themesNum = 0;
let json = null;
try
{
json = JSON.parse(str);
}
catch(er){log(er);}
if (json && typeof(json) == "object")
{
if ("hidden" in json)
{
hiddenNum = json.hidden.length;
for(let i = 0; i < hiddenNum; i++)
showHide(parseInt(json.hidden[i]), 1);
}
if ("watched" in json)
{
for(let id in json.watched)
{
for(let i = 0; i < json.watched[id].length; i++)
{
let ep = json.watched[id][i];
watched.add(id, ep);
watchedNum++;
$('div.entry[data-series-id="' + id + '"]').each(function(n, entry)
{
if (episodeTools.short(entry) == ep)
watched.update(entry, true);
});
}
}
watched.save(true);
}
if (!json.cookies)
json.cookies = {};
if ("settings" in json)
{
let save = false;
for(let i in json.settings)
{
let val = json.settings[i];
if (i in cs.listLegacy && !(i in Settings.prefsDef))
{
val = json.settings[i];
i = cs.listLegacy[i];
}
if (!(i in Settings.prefsDef))
{
if (!(i in json.cookies) && cs.list.indexOf(i) != -1)
json.cookies[i] = val;
continue;
}
if (!command(i, val))
{
settingsNum++;
Settings.prefs[i] = val;
reload = true;
save = true;
}
}
if (save)
Settings.save();
}
if ("cookies" in json)
{
for(let i in json.cookies)
{
if (cs.list.indexOf(i) == -1)
continue;
if (!command(i, json.cookies[i]))
{
settingsNum++;
cs(i, json.cookies[i]);
reload = true;
}
}
}
let enginesNew = [];
if ("customLinks" in json)
{
let changed = false;
for (i in json.customLinks)
{
enginesNum++;
changed = reload = true;
customLinks._list[i] = json.customLinks[i];
enginesNew.push(json.customLinks[i]);
}
if (changed)
ls("customLinks", customLinks._list);
}
if ("enginesHide" in json)
{
let changed = false;
let list = [];
for(let i = 0; i < json.enginesHide.length; i++)
{
if (enginesFind(json.enginesHide[i]) != -1 || enginesFind(json.enginesHide[i], enginesNew) != -1)
{
list[list.length] = json.enginesHide[i];
changed = reload = true;
engineHideNum++;
}
}
enginesHide = list;
if (changed)
ls("enginesHide", enginesHide);
}
if ("enginesSort" in json)
{
let changed = false;
enginesSort._list = [];
for(let i = 0; i < json.enginesSort.length; i++)
{
if (enginesFind(json.enginesSort[i]) != -1 || enginesFind(json.enginesSort[i], enginesNew) != -1)
{
changed = reload = true;
enginesSort._list.push(json.enginesSort[i]);
}
}
if (changed)
ls("enginesSort", enginesSort._list);
}
if ("info" in json)
{
let changed = false;
for(let i in json.info)
{
if (!(i in DB.info))
{
DB.info[i] = json.info[i];
changed = true;
}
}
if (changed)
DB.infoSave();
}
if ("epNumFix" in json)
{
let changed = false;
for(let i in json.epNumFix)
{
if (!(i in episodeNumberFix.list))
{
episodeNumberFix.list[i] = json.epNumFix[i];
changed = true;
}
}
if (changed)
episodeNumberFix.save();
}
if ("themes" in json)
{
let changed = false;
for(let i in json.themes)
{
if (!(i in Settings.themes._default))
{
Settings.themes.list[i] = json.themes[i];
changed = true;
themesNum++;
}
}
if (changed)
Settings.themes.save();
}
if ("customShows" in json)
{
let changed = false,
upgrade = versionsCompare(json.version, "1.71") < 0;
for(let i in json.customShows.l)
{
let data = json.customShows.l[i];
if (upgrade)
{
for (let n = 0; n < data[1].length; n++)
{
if (data[1][n].length == 6)
{
data[1][n][6] = data[1][n][5]; //custom show days of the week
data[1][n][5] = 1;
}
}
}
customShows._list.l[i] = data;
changed = true;
customShowsNum++;
}
//remove duplicate
let newData = {},
names = {};
for(let f in customShows._list.l)
{
let data = customShows._list.l[f],
name = data[0],
seen = {},
id = f;
if (name in names)
{
data[1] = [].concat(names[name].d[1], data[1]);
id = names[name].i;
}
data[1] = data[1].sort().filter(function(item)
{
var k = JSON.stringify(item);
return k in seen ? false : (seen[k] = true);
});
names[name] = {
i: f,
d: data
};
newData[id] = data;
}
customShows._list.l = newData;
if (changed)
{
customShows._list.i = Math.max(json.customShows.i, customShows._list.i);
customShows.save();
customShows.init(customShows._list);
customShows();
}
}
txt = settingsNum + " setting" + (settingsNum > 1 ? "s" : "") + " imported" + ((hiddenNum || watchedNum) ? " and marked " : "");
if (hiddenNum)
txt += hiddenNum + " show" + (hiddenNum > 1 ? "s" : "") + " as hidden";
if (watchedNum)
txt += (hiddenNum ? ", " : " ") + watchedNum + " as watched";
if (themesNum)
txt += (themesNum ? ", " : " ") + themesNum + " theme" + (themesNum > 1 ? "s" : "");
if (customShowsNum)
txt += (customShowsNum ? ", " : " ") + customShowsNum + " custom show" + (customShowsNum > 1 ? "s" : "");
}
alert(txt);
if (reload)
window.location.reload();
}
a.addEventListener("click", function restoreSettings_link_evtClick(e)
{
e.preventDefault();
_prompt({
callback: function(data)
{
setTimeout(function()
{
restore(data);
});
},
text: "Please enter the " + adeName + " settings text"
});
}, false);
content.append(span);
content.append('
More...
');
span = span.cloneNode(true);
i = span.firstChild;
a = $(".clearColors")[0];
if (a)
{
a = a.cloneNode(true);
i.parentNode.replaceChild(a, i.nextSibling);
span.title = "Did you make a backup?";
i.innerHTML = SVG.clear;
let moreOpt = $("div.moreOpt");
moreOpt.find("div").append(span);
moreOpt.on("click", function()
{
moreOpt.attr("opened", true);
});
}
},//Settings.create()
_backup: function Settings__backup()
{
let cookies = {},
str = "",
obj = {
version: adeVersion,
settings: Settings.prefs
},
add = function(name, o)
{
for(let i in o)
{
obj[name] = o;
break;
}
};
for(let i = 0; i < cs.list.length; i++)
{
let v = cs(cs.list[i]);
if (v !== null)
{
cookies[cs.list[i]] = v;
}
}
add("cookies", cookies);
add("hidden", _hidden);
add("watched", watched._list);
add("customLinks", customLinks._list);
add("enginesHide", enginesHide);
add("enginesSort", enginesSort._list);
add("info", DB.info);
add("epNumFix", episodeNumberFix.list);
add("themes", Settings.themes.getCustomThemes());
add("customShows", customShows._list);
str = JSON.stringify(obj);
return str;
},
backup: function Settings_backup()
{
let str = this._backup();
if (str)
_prompt({
callback: function(){},
text: adeName + " Settings \nYou can save it in a normal textfile and restore it to another computer/browser.",
value: str
});
else
alert("Nothing to backup");
},
callback: function Settings_callback(e, id, check)
{
Settings.prefs[id] = check ? 1 : 0;
Settings.save();
},
save: function Settings_save(f)
{
ls("settings", this.prefs);
},
show: function Settings_show(noBack)
{
/*
if (noBack)
Settings.box.attr("noback", "");
else
Settings.box.removeAttr("noback");
*/
hidePopups();
Settings.box.show();
setPopup(true);
},
hide: function Settings_hide()
{
Settings.box.hide();
setPopup(false);
Settings.box.find("div.moreOpt").removeAttr("opened");
},
colors:
{
default: [], //list of predefined colors
max: 100, //max num of colors to remember
inited: false,
add: function Settings_colors_add(color, save)
{
color = color.toUpperCase();
if (color == "FFFFFF" || this.default.indexOf(color) != -1 || Settings.prefs.lastColors.indexOf(color) != -1)
return;
let colors = Settings.prefs.lastColors;
colors[colors.length] = color;
if (colors.length + 1 > this.max)
colors.splice(0, colors.length - this.max);
this.css();
if (save)
this.save();
},
save: function Settings_colors_save(color)
{
Settings.save();
},
css: function Settings_colors_css()
{
let css = "",
colors = Settings.prefs.lastColors;
for(let i = 0; i < colors.length; i++)
css += ".soft_cust" + i + "{background-color:#" + colors[colors.length - i - 1] + ";display:inline-block}\n";
$(".colors").toggleClass("nopre", (!Settings.prefs.lastColorsLine || Settings.prefs.lastColorsLine > 19) ? true : false);
document.getElementById("customColorsCSS2").innerHTML = css;
$('.colors [class^="color soft_"]').each(function(i)
{
this.title = "#" + new Colors().setColor($(this).css( "background-color" )).HEX.toUpperCase();
});
},
init: function Settings_colors_init()
{
$("#detailsTemplate div.colors .color").each(function(i, e)
{
if (!this.classList.contains( "none" ))
Settings.colors.default[Settings.colors.default.length] = new Colors().setColor($(this).css( "background-color" )).HEX.toUpperCase();
});
let css = "",
style = document.createElement("style"),
style2 = document.createElement("style"),
span = document.createElement("span"),
box = document.createElement("div"),
last = $("#detailsTemplate .colors"),
colors = Settings.prefs.lastColors,
max = Math.min(Settings.prefs.lastColorsShow, Settings.prefs.lastColors.length);
$('.colors .none').each(function(i)
{
this.title = "Remove color";
});
$('.colors .picker').each(function(i)
{
this.title = "Custom color";
// this.classList.add("svg");
});
for(let i = 0; i < max; i++)
{
let cl = "soft_cust" + i;
css += "." + cl + "{display:none;}\n";
span = span.cloneNode(true);
span.className = "color " + cl;
span.setAttribute("i", i);
box.appendChild(span);
let br = (Settings.prefs.lastColorsLine && !((i+1) % Settings.prefs.lastColorsLine)) ? document.createTextNode("\n") : document.createTextNode(" ");
box.appendChild(br);
}
$("#customColorsCSS, #customColorsCSS2").remove();
let b = $(".customColors");
if (b.length)
b.html(box.innerHTML);
else
$("#detailsTemplate .colors").append(box);
style.innerHTML = css;
style.id = "customColorsCSS";
style2.id = "customColorsCSS2";
box.className = "customColors";
$("head").append(style);
$("head").append(style2);
let c = [];
for(let i = 0; i < colors.length; i++)
{
if (colors[i] && (""+colors[i]).match(/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/))
c[c.length] = colors[i].toUpperCase();
}
Settings.prefs.lastColors = c;
let that = Settings.colors;
that.css();
if (that.inited)
return;
$( document ).off( "mouseover", ".color");
$( document ).off( "mouseout", ".color");
let coltimer;
$( document ).on( "mouseover", ".colors", function(e)
{
clearTimeout(coltimer);
if (e.target.classList.contains("color"))
{
var $this = $( e.target );
assignColor( $this.parents("div.entry").data( "series-id" ), $this.hasClass( "none" )? "" : $this.css( "background-color" ) );
}
});
$( document ).on( "mouseout", ".colors", function(){
clearTimeout(coltimer);
let $this = $(this);
coltimer = setTimeout(function(){loadColor( $this.parents("div.entry").data( "series-id" ) );}, 100);
});
$( document ).on( "mousedown", "div.colors .color", function(e)
{
if (e.which != 2)
return;
let col = new Colors().setColor($(this).css( "background-color" )).HEX.toUpperCase(),
index = Settings.prefs.lastColors.indexOf(col);
if (index != -1)
{
Settings.prefs.lastColors.splice(index, 1);
Settings.colors.css();
Settings.colors.save();
}
e.preventDefault();
});
that.inited = true;
}//Settings.colors.init()
},//Settings.colors
themes:
{
_default: {
"" : {
name: "Default",
isDark: false,
css: null
},
dark: {
name: "Dark",
isDark: true,
css: multiline(function(){/*
/*
Dark Theme
*//*
body
{
background-color: #191919 !important;
}
body,
.header h4,
#account-popup-content,
#settings-popup .content,
#manage-cushows-popup-content,
#manage-links-popup-content,
#changesLogBox
{
color: #E0DEDE;
}
body.archive
{
background-color: #292929 !important;
}
a
{
color: #737373;
}
.title:hover
{
background: #D2D2D2 !important;
}
#searchbar
{
background-color: rgb(76, 76, 76);
}
#account-popup-content,
#settings-popup .content,
#manage-cushows-popup-content,
#manage-links-popup-content,
#changesLogBox
{
background: rgb(76, 76, 76) !important;
}
#searchResults a
{
color: #D2D2D2;
fill: #D2D2D2;
}
svg,
#account-popup-content .content a,
#settings-popup .content a,
#manage-cushows-popup-content a,
#manage-links-popup-content a,
#changesLogBox,
#noChangesLog > a
{
color: #D2D2D2 !important;
fill: #D2D2D2 !important;
}
.close:hover,
.back:hover,
.back:hover svg,
#cushows-list > li:hover,
#cushows-list > li:hover *:not(.color),
#cushows-list.opened > li.opened,
#cushows-list.opened > li.opened *:not(.color),
#cushows-list.opened > li.opened .color > .colors,
#manage-links-popup .content > div.dragging:not(.hide),
#manage-links-popup .content > div.dragging:not(.hide) *,
#manage-links-popup .content:not(.dragging) > div:hover,
#manage-links-popup .content:not(.dragging) > div:hover *
{
color: rgb(76, 76, 76) !important;
fill: rgb(76, 76, 76) !important;
}
#cushows-list > li:hover,
#cushows-list.opened > li.opened,
#cushows-list.opened > li.opened .color > .colors,
#manage-links-popup .content > div.dragging:not(.hide),
#manage-links-popup .content:not(.dragging) > div:hover
{
background-color: #D2D2D2;
border: 1px dotted grey;
}
div.entry:not([color]) svg
{
fill: white !important;
}
div.entry[color="black"] svg,
.cl_added > span:first-child,
.cl_changed > span:first-child,
.cl_removed > span:first-child,
.cl_notfixed > span:first-child,
.cl_fixed > span:first-child
{
color: black;
fill: black !important;
}
span.button,
.header,
.header h4
{
background: rgb(112, 112, 112) !important;
}
.details a,
.day a
{
color: inherit !important;
}
.header a
{
color: inherit;
}
body.collapseMulti div.day:not(.expand):not(.opened) div.entry.multif div.title:after
{
background-color: white;
border-left: 1px solid black;
}
.details:hover,
.engines:hover
{
background:none !important;
}
div.date
{
color: #8c8c8c;
background-color: #4c4c4c;
}
div.today div.date
{
background-color: rgb(190, 150, 0);
}
div.today div.date
{
color: black;
}
div.day,
body.archive div.day
{
border: 1px solid #595959;
}
body.archive div.day
{
background-color: #191919;
}
.entry:not([color="white"]) div.details > span.engines > br + div.tools,
.entry:not([color="white"]) div.details,
.entry:not([color="white"]) div.colors,
div.entry
{
border-top: 1px dashed #4c4c4c;
}
/* highlight opened entry *//*
.entry[opened]
{
border: 1px solid white;
border-top: 1px solid white;
}
/*
.entry[opened][color="black"]
{
border: 1px solid black;
border-top: 1px solid black;
}
*//*
#resultsBecauseNoOneChecks,
#searchResults .description
{
color: #b9b2b2;
}
#cushows-list > li.updated,
#cushows-list > li.new
{
border-width: 1px;
}
#cushows-list > li.edit
{
border: 1px solid white;
}
#cushows-list > li.selected:not(.edit)
{
border: 1px dotted white;
}
#cushows-list > li.selected:not(.edit)
{
color: forestgreeen;
}
#cushows-list > li.edit.delete,
#cushows-list > li.edit.delete > *
{
color: coral;
}
#searchResults div.entry
{
border-color: #6c6c6c;
}
#searchResults div.entry.separating
{
border-color: #aaa;
}
.desc > div.entry
{
border-top: none;
border-bottom: 1px dashed #ccc;
}
.desc > div.entry.separating
{
border-bottom: 1px solid #555;
}
:not(.desc) > div.entry.separating
{
border-top: 1px solid;
}
#searchIcon > svg
{
fill: #737373 !important;
vertical-align: middle;
}
.cookieIconHoles
{
fill: #000;
}
.warning.info,
.warning.info > a
{
color: #FFBFBF;
}
div.undoBar *
{
color: black;
}
/*
END DARK THEME
*//*
*/}, true)
}//dark theme
},//themes.list._default
list: {},
init: function Settings_themes_nit()
{
for (let theme in this._default)
{
this.list[theme] = this._default[theme];
}
let themes = ls("themes") || {};
for(let theme in themes)
{
this.list[theme] = themes[theme];
}
let head = document.getElementsByTagName("head")[0];
for(let cssName in this.list)
{
if (!this.list[cssName].css)
continue;
let name = cssName.replace(/[^a-zA-Z0-9_-]/g, "_"),
id = "theme_" + name,
style = document.getElementById(id) || document.createElement("style"),
reg = function(a)
{
let r = "body." + id;
if (a.toLowerCase() != "body")
r += " " + a;
return r;
};
style.id = id;
style.innerHTML = this.list[cssName].css.replace(/^(?!\*\/)(body|\w|[\.#\[\:\$@\*])/gm, reg).replace(/(\/\*([\s\S]*?)\*\/)|(\/\/(.*)$)/gm, '').replace(/[\n\t]*/g, "");
head.appendChild(style);
}
this.quickOverrideInit();
// this.quickOverride();
}, //Settings.themes.init()
load: function Settings_themes_load(theme)
{
if (typeof(theme) == "undefined")
{
theme = Settings.prefs.theme;
}
else
{
Settings.prefs.theme = theme;
Settings.save();
}
let data = Settings.themes.list[theme];
if (!data)
data = theme ? Settings.themes.list.dark : Settings.themes.list[""];
let body = $("body"),
className = "theme_" + theme;
if (Settings.themes.prev)
body.toggleClass(Settings.themes.prev, false);
if (theme)
{
body.toggleClass(className, true);
Settings.themes.prev = className;
}
let disqusFrameRemoved = false,
disqusDiv = document.getElementById("disqus_thread");
disqusDiv && disqusDiv.addEventListener('DOMNodeInserted', e =>
{
if (e.target.tagName != "IFRAME")
return;
// $("#disqus_recommendations").remove();
e.target.addEventListener("load", e=>
{
// if (!disqusFrameRemoved && disqusDiv.querySelector("iframe") === e.target)
// return e.target.parentNode.removeChild(e.target);
if (!e.target.src)
try{return e.target.parentNode.removeChild(e.target);}catch(er){return;} //remove ads
try
{
e.target.contentWindow && e.target.contentWindow.postMessage({id: "ade", func: "disqusTheme", args: [data.isDark], return: null}, "https://disqus.com");
}
catch(er){console.log(er);}
});
}, false);
$("#disqus_thread").find('iframe[src^="https://disqus.com"]').each(function(o)
{
try
{
this.contentWindow.postMessage({id: "ade", func: "disqusTheme", args: [data.isDark], return: null}, "https://disqus.com");
}
catch(er){console.log(er);}
});
$("select#theme").val(theme);
},//Settings.themes.load()
getCustomThemes: function Settings_themes_getCustomThemes()
{
let themes = Object.assign({}, this.list);
for(let t in this._default)
{
if (t in themes && themes[t] == this._default[t])
delete themes[t];
}
return themes;
},
quickOverrideStyle: [],
quickOverrideInit: function Settings_themes_quickOverrideInit()
{
if (this.quickOverride.inited)
return;
for( let i in Settings.prefs.themeColors)
{
let id = "CSS_override_" + i;
if (document.getElementById(id))
continue;
this.quickOverrideStyle[i] = document.createElement("style");
this.quickOverrideStyle[i].id = id;
document.getElementsByTagName("head")[0].appendChild(this.quickOverrideStyle[i]);
}
this.quickOverride.inited = true;
},
quickOverride: function Settings_themes_quickOverride(data, commonOnly)
{
if (typeof(data) != "object")
data = Settings.prefs.themeColors;
for(let i in data)
{
let val = "" + data[i],
c1 = "",
c2 = "",
r = this.quickOverrideTempl._common.css,
css = "";
if (val.length == 3)
{
val = val[0] + val[0] + val[1] + val[1] + val[2] + val[2];
}
c1 = val;
if (val)
c2 = new Colors().setColor(val).rgbaMixBlack.luminance > 0.22 ? "000" : "FFF";
if (val && !commonOnly)
r += this.quickOverrideTempl[i].css || "";
r = r .replace(/\{ID\}/g, i)
.replace(/\{C1\}/g, c1)
.replace(/\{C2\}/g, c2);
if (val)
css += r;
this.quickOverrideStyle[i].innerHTML = css;
if (this.quickOverrideStyle[i].nextSibling)
{
document.getElementsByTagName("head")[0].appendChild(this.quickOverrideStyle[i]);
}
}
},//Settings.themes.quickOverride()
quickOverrideTempl:
{
_common:
{
css: multiline(function(){/*
#themeColorBox_{ID} > .color
{
background-color: #{C1} !important;
color: #{C2} !important;
}
/*
#themeColorBox_{ID} > .color
{
border-color: #{C2} !important;
}*//*
*/})
},
today:
{
css: multiline(function(){/*
.example_today,
div.today > .date
{
color: #{C1} !important;
fill: #{C1} !important;
}
*/}),
title: "Leave empty to use theme's color",
label: "Today text",
sample: "today"
},
todayBg:
{
css: multiline(function(){/*
.example_today,
div.today > .date
{
background-color: #{C1} !important;
}
*/}),
title: "Leave empty to use theme's color",
label: "Today background",
sample: "today"
},
todayBorder:
{
css: multiline(function(){/*
.example_today,
div.today
{
border-color: #{C1} !important;
-webkit-box-shadow: 0px 0px 10px 0px #{C1} !important;
-moz-box-shadow: 0px 0px 10px 0px #{C1} !important;
box-shadow: 0px 0px 10px 0px #{C1} !important;
}
*/}),
title: "Leave empty to use theme's color",
label: "Today border",
sample: "today"
},
bg:
{
css: multiline(function(){/*
.example_text,
.example_day,
body,
body[class*="theme_"]
{
background-color: #{C1} !important;
}
*/}),
title: "Leave empty to use theme's color",
label: "Background",
// sample: "text,day"
sample: "text"
},
text:
{
css: multiline(function(){/*
.example_text,
body #content > :not(.popup) #searchIcon > svg,
body[class*="theme_"] > :not(.popup) #searchIcon > svg,
body #content > :not(.popup),
body[class*="theme_"] > :not(.popup) svg,
body #content > :not(.popup) svg
body[class*="theme_"] > :not(.popup),
body #content > :not(.popup) a
{
color: #{C1} !important;
fill: #{C1} !important;
}
*/}),
/* css: multiline(function(){/*
.example_text,
body #content > :not(.popup) > *:not(.days),
body #content > :not(.popup) > *:not(.days) *,
body[class*="theme_"] > :not(.popup) > *:not(.days) *,
body #content > :not(.popup) > :not(.days),
body #content > :not(.popup) > :not(.days) a,
body[class*="theme_"] > :not(.popup) > :not(.days) a
{
color: #{C1} !important;
fill: #{C1} !important;
}
*/
// }),
title: "Leave empty to use theme's color",
label: "Text",
sample: "text"
},
/* day:
{
css: multiline(function(){/*
.example_day,
div.entry:not([color]),
body[class*="theme_"] div.entry:not([color])
{
color: #{C1} !important;
fill: #{C1} !important;
}
*/
/* }),
title: "Leave empty to use theme's color",
label: "Day text",
sample: "day"
},
*/
date:
{
css: multiline(function(){/*
.example_date,
body div.day:not(.today) div.date,
body[class*="theme_"] div.day:not(.today) div.date
{
color: #{C1} !important;
fill: #{C1} !important;
}
*/}),
title: "Leave empty to use theme's color",
label: "Date text",
sample: "date"
},
dateBg:
{
css: multiline(function(){/*
.example_date,
body div.day:not(.today) div.date,
body[class*="theme_"] div.day:not(.today) div.date
{
background-color: #{C1} !important;
}
.example_date,
body div.day:not(.today),
body[class*="theme_"] div.day:not(.today)
{
border-color: #{C1} !important;
}
*/}),
title: "Leave empty to use theme's color",
label: "Date background",
sample: "date"
}
},//quickOverrideTempl
save: function themesSave()
{
ls("themes", this.getCustomThemes());
},
},//themes
lastUpdate: new Date(),
lastUpdateDiv: null,
lastUpdateShow: function Settings_lastUpdateShow()
{
if (!this.lastUpdateDiv)
{
this.lastUpdateDiv = document.createElement("span");
this.lastUpdateDiv.className = "lastupdate";
const footer = document.querySelector("div.footer");
footer && footer.appendChild(this.lastUpdateDiv);
}
this.lastUpdateDiv.textContent = "Page updated " + this.lastUpdate;
}
};//Settings
Object.seal(Settings);
let episodeTools = (function()
{
const SEID = 1000000;
function fromNode(node)
{
let r;
if (node._episode)
r = node._episode;
else
{
r = node._title && node._title._titleDefault ? node._title._titleDefault : $(node).find("div.title").text();
r = r.substring(r.lastIndexOf(" ") + 1).replace(/\s+$/g, "").trim();
if (!r.match(/(^S[0-9]+)?E[0-9]+$/i))
return "";
}
return r;
}
return {
id: function episodeTools_id(s, e)
{
s = this.split(s, e);
e = s[1];
s = ~~s[0];
return typeof(e) == "undefined" ? s : s * SEID + ~~e;
},
id2se: function episodeTools_id2se(se)
{
se = ~~se;
return [Math.floor(se / SEID), se % SEID];
},
full: function episodeTools_full(s, e)
{
if (s instanceof HTMLElement)
s = fromNode(s);
if (typeof(e) == "undefined" && typeof(s) == "number" && s >= SEID)
s = this.id2se(s);
if (s instanceof Array)
{
e = s[1];
s = s[0];
}
if (typeof(e) == "undefined" && typeof(s) == "string")
return s.replace(/^\s*(S?0*([0-9]+)?E)?0*([0-9]+)\s*$/i, function(a, b, c, d)
{
return (~~c ? "S" + pad(~~c) : "") + "E" + pad(~~d);
});
if (typeof(e) == "undefined")
{
e = s;
s = 0;
}
s = ~~s;
e = ~~e;
return (s ? "S" + pad(s) : "") + "E" + pad(e);
},
short: function episodeTools_short(s, e)
{
if (s instanceof HTMLElement)
s = fromNode(s);
if (typeof(e) == "undefined" && typeof(s) == "number" && s >= SEID)
s = this.id2se(s);
if (s instanceof Array)
{
e = s[1];
s = s[0];
}
if (typeof(e) == "undefined" && typeof(s) == "string")
return s.replace(/^\s*(S?0*([0-9]+))?E0*([0-9]+)|0*([0-9]+)\.0*([0-9]+)\s*$/i, "$2$4E$3$5").replace(/^E/, "");
return ("" + (typeof(e) == "undefined" ? ~~s : ~~s + "E" + ~~e)).replace(/^0*E*/, "");
},
split: function episodeTools_split(s, e)
{
if (s instanceof HTMLElement)
s = fromNode(s);
if (typeof(e) == "undefined" && typeof(s) == "number" && s >= SEID)
s = this.id2se(s);
if (s instanceof Array)
{
e = s[1];
s = s[0];
}
let m = ("" + (typeof(e) == "undefined" ? s : s + "E" + e)).match(/^\s*(S?0*([0-9]+)?E+)?0*([0-9]+)\s*$/i);
if (m)
return [~~m[2], ~~m[3]];
return typeof(e) == "undefined" ? [0, ~~s] : [~~s, ~~e];
}
};
})();
function fileLoad(callback, ext)
{
let f = document.createElement("input");
f.type = "file";
if (typeof(ext) == "undefined")
ext = ".json";
if (ext)
f.setAttribute("accept", ext);
function readFile(e)
{
f.removeEventListener("change", readFile, false);
let files = f.files;
if (!f.files.length)
{
alert('Please select a file!');
return;
}
let reader = new FileReader();
reader.onloadend = function(evt)
{
if (evt.target.readyState == FileReader.DONE)
{
callback(evt.target.result);
}
};
let blob = f.files[0].slice(0, f.files[0].size);
reader.readAsBinaryString(blob);
}
f.addEventListener("change", readFile, false);
f.click();
}
function fileSave(name, data, type)
{
type = type ? type : 'text/json';
let blob = new Blob([data], {type: type}),
a = document.createElement("a");
a.download = name;
a.isTrigger = true;
a.href = window.URL.createObjectURL(blob);
a.dataset.downloadurl = [type, a.download, a.href].join(':');
$("#account-popup").append(a);
a.click();
a.parentNode.removeChild(a);
}
function exportGetColors()
{
return Object.keys(DB.savedColors).map(function(i)
{
if (i.match(/[^0-9]/) || !DB.savedColors[i].match(/^#([0-9A-F]{6})|FFFFFF$/i))
return;
return i + "=" + DB.savedColors[i].trim();
}).join(";");
}
function pad(t, s, n)
{
n = n || 2;
n = Math.max(n, ~~(("" + t).length));
s = String(s || "0").repeat(n);
return (s + t).substr(-n);
}
function dateTimestamp()
{
let d = new Date();
return d.getFullYear() + pad(d.getMonth()+1) + pad(d.getDate()) + pad(d.getHours()) + pad(d.getMinutes()) + pad(d.getSeconds());
}
function enginesBackup()
{
if (!enginesBackup.backup)
enginesBackup.backup = window.engines;
}
function enginesRestore()
{
if (enginesBackup.backup)
{
window.engines = enginesBackup.backup;
enginesBackup.backup = null;
}
}
function enginesAdd(id)
{
for(let i = 0; i < _engines.length; i++)
{
if (_engines[i].name == id || _engines[i].host == id)
return;
}
for(let i = 0; i < engines.length; i++)
{
if (engines[i].name == id || engines[i].host == id)
{
_enginesList.push(engines[i].host);
_engines.push(engines[i]);
Settings.pref("middleClick", _enginesList);
return;
}
}
}
function enginesRemove(id)
{
for(let i = 0; i < _engines.length; i++)
{
if (_engines[i].name == id || _engines[i].host == id)
{
let n = _enginesList.indexOf(_engines[i].host);
if (n != -1)
_enginesList.splice(n, 1);
Settings.pref("middleClick", _enginesList);
_engines.splice(i, 1);
return;
}
}
}
function enginesCheck(id)
{
for(let i = 0; i < _engines.length; i++)
{
// if (_engines[i].name == id || _engines[i].host == id)
if (_engines[i].host == id)
return i;
}
return -1;
}
function enginesFind(id, obj, field)
{
obj = typeof(obj) == "undefined" ? window.engines : obj;
for(let i = 0; i < obj.length; i++)
{
if ((field && obj[i][field] == id) || (!field && (obj[i].name == id || obj[i].host == id)))
return i;
}
return -1;
}
function enginesSort(list, save)
{
if (typeof(list) == "undefined")
{
list = ls("enginesSort") || [];
save = true;
}
let newList = [],
newEnginesList = [],
engs = [window.engines, customLinks._list];
for(let i = 0; i < list.length; i++)
{
for(let n = 0; n < engs.length; n++)
{
let index = enginesFind(list[i], engs[n], "host");
if (index == -1 || newList.indexOf(engs[n][index].host) != -1)
continue;
newEnginesList[newEnginesList.length] = engs[n][index];
newList[newList.length] = engs[n][index].host;
break;
}
}
for(let i = 0; i < window.engines.length; i++)
{
if (newList.indexOf(window.engines[i].host) == -1)
{
newEnginesList[newEnginesList.length] = window.engines[i];
newList[newList.length] = window.engines[i].host;
}
}
for(let i in customLinks._list)
{
if (newList.indexOf(i) == -1)
{
newEnginesList[newEnginesList.length] = customLinks._list[i];
newList[newList.length] = i;
}
}
if (save)
enginesSort._list = newList;
window.engines = newEnginesList;
}
enginesSort.changed = function()
{
let list = [];
for (let i = 0; i < enginesDefault.length; i++)
{
list[list.length] = enginesDefault[i].host;
}
for (let i in customLinks._list)
{
if (list.indexOf(i) == -1)
list[list.length] = i;
}
return !isEqual(list, enginesSort._list);
};
function isEqual (a, b)
{
if (typeof(a) == "undefined" || typeof(b) == "undefined")
return false;
for(let i in a)
{
if (typeof(a[i]) == "object")
{
if (!isEqual(a[i], b[i]))
return false;
}
else if (!(i in b) || a[i] != b[i])
return false;
}
for(let i in b)
{
if (typeof(b[i]) == "object")
{
if (!isEqual(a[i], b[i]))
return false;
}
else if (!(i in a) || a[i] != b[i])
return false;
}
return true;
}
function cleanName(id)
{
return id !== null ? id.replace(/[^a-zA-Z0-9-_]/g, "_") : "";
}
function getHost(url)
{
let a = document.createElement('a');
a.href = url;
return a.hostname;
}
function engineFixHost(engine)
{
if (engine.host)
return;
engine.host = getHost(engine.href);
}
function showHide(id, t)
{
let hidden = _hidden.indexOf(id);
if (typeof(t) == "undefined")
return hidden != -1;
if (t == 2)
t = hidden == -1 ? 1 : 0;
switch(t)
{
case 0:
_hidden.splice(hidden, 1);
if (!DB.savedColors[id])
DB.infoRemove(id);
hidden = false;
break;
case 1:
if (hidden == -1)
{
_hidden.push(id);
DB.infoAdd(id);
}
hidden = true;
break;
}
let css = $("#css" + id);
if (hidden)
{
if (!css.length)
{
let style = "";
$(style).appendTo("body");
}
}
else
css.remove();
ls("hidden", _hidden);
return hidden;
}
function command(id, val)
{
if (!command.list[id])
return false;
try
{
command.list[id].func({preventDefault:function(){},stopPropagation:function(){}}, val);
}
catch(er)
{
return false;
}
return true;
}
command.list = {};
command.add = function(id, objId, func)
{
command.list[id] = {
id: id,
objId: objId,
func: func
};
};
/* watched checkbox */
function watched(entry)
{
if (entry._input.checked)
watched.add(entry.getAttribute("data-series-id"), entry);
else
watched.remove(entry.getAttribute("data-series-id"), entry);
watched.update(entry, entry._input.checked);
}
watched._list = ls("watched") || {};
watched._saving = false;
watched.add = function(id, episode)
{
episode = episodeTools.short(episode);
if (!watched._list[id])
watched._list[id] = [];
if (watched._list[id].indexOf(episode) == -1)
watched._list[id].push(episode);
watched.save();
};
watched.remove = function(id, episode)
{
if (!watched._list[id])
return;
episode = episodeTools.short(episode);
let n = watched._list[id].indexOf(episode);
if (n == -1)
return;
watched._list[id].splice(n, 1);
if (!watched._list[id].length)
delete watched._list[id];
watched.save();
};
watched.save = function(f)
{
if (watched._saving && !f)
return;
function func()
{
watched._saving = false;
ls("watched", watched._list);
}
clearTimeout(watched._saving);
if (f)
func();
else
watched._saving = setTimeout(func, 500);
};
watched.has = function(entry)
{
let id = entry.getAttribute("data-series-id");
return watched._list[id] && watched._list[id].indexOf(episodeTools.short(entry)) != -1;
};
watched.update = function(entry, enable)
{
if (enable)
entry.setAttribute("watched", "");
else
entry.removeAttribute("watched");
let span = $(entry).find(".title > span")[0];
entry.title = span.lastChild ? span.lastChild.textContent : span.textContent;// + " (" + text + ")";
entry._input.checked = enable;
watched.checkboxTooltip(entry);
};
watched.checkboxTooltip = function(entry)
{
let input = entry.querySelector('input[type="checkbox"]');
input.title = input.checked ? "Watched" : "Not watched";
if (entry.parentNode.id == "searchResults" || entry.classList.contains("searchResult"))
input.title += "\n\nHold SHIFT key to check/uncheck all previous episides";
};
watched.attach = function(i,entry)
{
if (entry._input)
return;
let input = document.createElement("input"),
id = entry.dataset.seriesId,
episodeID = episodeTools.id(entry);
setEpisodes([entry]);
input.type = "checkbox";
input.checked = watched.has(entry);
entry._input = input;
input.addEventListener("mouseover", function(e)
{
watched.checkboxTooltip(entry);
}, false);
input.addEventListener("click", function(ev)
{
let isBatch = ev.shiftKey && (entry.parentNode.id == "searchResults" || entry.classList.contains("searchResult") && document.getElementById("searchBecauseNoOneChecks").value.trim() == "info:" + id);
$('div.entry[data-series-id="' + id + '"]').each(function(i, _entry)
{
let _episodeID = episodeTools.id(_entry);
if (_episodeID == episodeID || (isBatch && _episodeID < episodeID))
{
_entry._input.checked = input.checked;
watched(_entry);
}
});
}, false);
let title = $(entry).find(".title")[0],
text = "",
div = null;
if (!title)
return;
for(let i = 0; i < title.childNodes.length; i++)
{
if (title.childNodes[i].nodeType == 3)
{
text += title.childNodes[i].textContent;
}
else
div = title.childNodes[i].cloneNode(true);
}
title.innerHTML = "";
title.appendChild(input);
// if (div)
// $(title).append(div)
let span = document.createElement("span");
title.appendChild(span);
if (div)
span.appendChild(div);
let titleSpan = document.createElement("span");
titleSpan.textContent = text.trim();
span.appendChild(titleSpan);
if (!entry._title)
{
entry._title = titleSpan;
entry._title._titleDefault = titleSpan.textContent;
entry.setAttribute("data-title", titleSpan.textContent);
}
entry._title.textContent = episodeNumberFix(id, entry._title.textContent);
watched.update(entry, input.checked);
}; //watched.attach()
/* custom links */
function customLinks(obj)
{
}
customLinks._list = ls("customLinks") || {};
customLinks.show = function(noBack)
{
let div = $(customLinks.div);
hidePopups();
div.show();
setPopup(true);
};
customLinks.hide = function()
{
$(customLinks.div).hide();
setPopup(false);
};
customLinks.manager = function customLinksManager(callback)
{
if (customLinks.div)
return callback ? callback() : true;
let html = multiline(function(){/*
{SVG-BACK}
Links Manager
{SVG-CLOSEHOVER}
{SVG-CLOSE}
*/});//html
let popup = $(html).appendTo("#content");
customLinks.div = popup[0];
$(popup).find("[id^=account]").each(function()
{
this.id = this.id.replace("account", "manage-links");
});
let content = $(popup).find(".content").html("");
html = multiline(function(){/*