def add_to_trakt_collection(type, imdb_id, title): Trakt.configuration.defaults.app(id=8835) Trakt.configuration.defaults.client( id="aa1c239000c56319a64014d0b169c0dbf03f7770204261c9edbe8ae5d4e50332", secret= "250284a95fd22e389b565661c98d0f33ac222e9d03c43b5931e03946dbf858dc") Trakt.on('oauth.token_refreshed', on_token_refreshed) if not plugin.get_setting('authorization'): if not authenticate(): return authorization = json.loads(plugin.get_setting('authorization')) with Trakt.configuration.oauth.from_response(authorization, refresh=True): result = Trakt['sync/collection'].add( {type: [{ 'ids': { 'imdb': imdb_id } }]}) if type == "shows": result = Trakt['sync/history'].add( {type: [{ 'ids': { 'imdb': imdb_id } }]}) dialog = xbmcgui.Dialog() dialog.notification("Trakt: add to collection", title)
def __init__(self, wf): self.wf = wf # load authorization from settings if 'access_token' in self.wf.settings: self.authorization['access_token'] = self.wf.settings[ 'access_token'] self.authorization['created_at'] = self.wf.settings['created_at'] self.authorization['expires_in'] = self.wf.settings['expires_in'] self.authorization['refresh_token'] = self.wf.settings[ 'refresh_token'] self.authorization['scope'] = self.wf.settings['scope'] self.authorization['token_type'] = self.wf.settings['token_type'] else: self.authorization = {} # bind trakt events Trakt.on('oauth.token_refreshed', self.__on_token_refreshed) # set base url Trakt.base_url = 'https://api-v2launch.trakt.tv' # set app defaults Trakt.configuration.defaults.app(id=self.__app_id) # set client defaults Trakt.configuration.defaults.client(id=self.__client_id, secret=self.__client_secret) # set oauth defaults Trakt.configuration.defaults.oauth(refresh=True)
def __init__(self, config) -> None: super().__init__(config) self.now_playing_metadata = None self.now_playing_description = None self.current_player = None self.playback_rate = None self.last_elapsed_time = None self.last_elapsed_time_timestamp = None self.netflix_titles = {} self.itunes_titles = {} self.amazon_titles = {} self.app_handlers = { 'com.apple.TVShows': self.handle_tvshows, 'com.apple.TVWatchList': self.handle_tv_app, 'com.apple.TVMovies': self.handle_movies, 'com.netflix.Netflix': self.handle_netflix, 'com.amazon.aiv.AIVApp': self.handle_amazon } Trakt.configuration.defaults.client( id= 'dc705f550f50706bdd7bd55db120235cc68899dbbfb4fbc171384c1c1d30d7d4', secret= 'f9aba211b886ea9f31a57c952cd0b5ab702501808db50584a24a5cc07466179d') Trakt.on('oauth.token_refreshed', self.on_trakt_token_refreshed) self.authenticate_trakt()
def __init__(self): self.is_authenticating = Condition() self.authorization = None # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed)
def __init__(self, force=False): logger.debug("Initializing.") proxyURL = checkAndConfigureProxy() if proxyURL: Trakt.http.proxies = { 'http': proxyURL, 'https': proxyURL } Trakt.configuration.defaults.app( id=999 ) # Configure Trakt.configuration.defaults.client( id=self.__client_id, secret=self.__client_secret ) # Bind event Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.oauth( refresh=True ) if getSetting('authorization') and not force: self.authorization = loads(getSetting('authorization')) else: last_reminder = getSettingAsInt('last_reminder') now = int(time.time()) if last_reminder >= 0 and last_reminder < now - (24 * 60 * 60) or force: self.login()
def __init__(self, force=False): logger.debug("Initializing.") proxyURL = checkAndConfigureProxy() if proxyURL: Trakt.http.proxies = {'http': proxyURL, 'https': proxyURL} Trakt.configuration.defaults.app(id=999) # Configure Trakt.configuration.defaults.client(id=self.__client_id, secret=self.__client_secret) # Bind event Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.oauth(refresh=True) if getSetting('authorization') and not force: self.authorization = loads(getSetting('authorization')) else: last_reminder = getSettingAsInt('last_reminder') now = int(time.time()) if last_reminder >= 0 and last_reminder < now - (24 * 60 * 60) or force: self.login()
def __init__(self): logger.debug("Initializing.") proxyURL = checkAndConfigureProxy() if proxyURL: Trakt.http.proxies = {'http': proxyURL, 'https': proxyURL} # Get user login data self.__pin = getSetting('PIN') if getSetting('authorization'): self.authorization = loads(getSetting('authorization')) else: self.authorization = {} # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.app(id=999) # Configure Trakt.configuration.defaults.client(id=self.__client_id, secret=self.__client_secret) #Set defaults Trakt.configuration.defaults.oauth(refresh=True) if not self.authorization: self.authenticate()
def add_to_trakt_watchlist(type,imdb_id,title): Trakt.configuration.defaults.app( id=8835 ) Trakt.configuration.defaults.client( id="aa1c239000c56319a64014d0b169c0dbf03f7770204261c9edbe8ae5d4e50332", secret="250284a95fd22e389b565661c98d0f33ac222e9d03c43b5931e03946dbf858dc" ) Trakt.on('oauth.token_refreshed', on_token_refreshed) if not __settings__.getSetting('authorization'): if not authenticate(): return authorization = loads(__settings__.getSetting('authorization')) with Trakt.configuration.oauth.from_response(authorization, refresh=True): result = Trakt['sync/watchlist'].add({ type: [ { 'ids': { 'tmdb': imdb_id } } ] }) dialog = xbmcgui.Dialog() dialog.notification("Trakt: add to watchlist",title)
def __init__(self): logger.debug("Initializing.") proxyURL = checkAndConfigureProxy() if proxyURL: Trakt.http.proxies = { 'http': proxyURL, 'https': proxyURL } if getSetting('authorization'): self.authorization = loads(getSetting('authorization')) else: self.authorization = {} # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.app( id=999 ) # Configure Trakt.configuration.defaults.client( id=self.__client_id, secret=self.__client_secret ) #Set defaults Trakt.configuration.defaults.oauth( refresh=True )
def __init__(self): self.is_authenticating = Condition() self.authorization = None self.recent_days = 30 self.radarr_use = True self.radarr_address = '' self.radarr_apikey = '' self.radarr_tag_id = False self.radarr_unmonitor = True self.sonarr_use = True self.sonarr_address = '' self.sonarr_apikey = '' self.sonarr_tag_id = False self.sonarr_unmonitor = True self.medusa_use = False self.medusa_address = '' self.medusa_username = '' self.medusa_password = '' # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed)
def update_history(): # result = tvshow_manager.to_watch() # print result trakt_manager = Trakt() tvshow_manager = TVShowTime() print 'Fetching Trakt.tv watched history...' history = trakt_manager.get_history() checkin_list = [] list_shows = {} for ep in history: show = { "show_id": ep['show']['ids']['tvdb'], "season": ep['episode']['season'], "episode": ep['episode']['number'] } # filter by greater ep and season filter_list = filter( lambda x: x['season'] >= show['season'] and x['show_id'] == show[ 'show_id'] and x['episode'] > show['episode'], checkin_list) if len(filter_list) == 0: checkin_list.append(show) print 'Saving progress on TVShowTime' print tvshow_manager.save_progress(checkin_list)
def init_trakt(cls): config = Configuration.advanced['trakt'] # Build timeout value timeout = ( config.get_float('connect_timeout', 6.05), config.get_float('read_timeout', 24) ) # Client Trakt.configuration.defaults.client( id='c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61', secret='bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65' ) # Application Trakt.configuration.defaults.app( name='trakt (for Plex)', version=PLUGIN_VERSION ) # Http Trakt.base_url = ( config.get('protocol', 'https') + '://' + config.get('hostname', 'api.trakt.tv') ) Trakt.configuration.defaults.http( timeout=timeout ) # Configure keep-alive Trakt.http.keep_alive = config.get_boolean('keep_alive', True) # Configure requests adapter Trakt.http.adapter_kwargs = { 'pool_connections': config.get_int('pool_connections', 10), 'pool_maxsize': config.get_int('pool_size', 10), 'max_retries': Retry( total=config.get_int('connect_retries', 3), read=0 ) } Trakt.http.rebuild() # Bind to events Trakt.on('oauth.refresh', cls.on_trakt_refresh) Trakt.on('oauth.refresh.rejected', cls.on_trakt_refresh_rejected) log.info( 'Configured trakt.py (timeout=%r, base_url=%r, keep_alive=%r, adapter_kwargs=%r)', timeout, Trakt.base_url, Trakt.http.keep_alive, Trakt.http.adapter_kwargs, )
def handler(event, context): parser = ConfigParser.ConfigParser() parser.read('config.ini') trakt_manager = Trakt() if not trakt_manager.is_token_valid(): print 'Your access has been revoked or invalidated, please authenticate again.' else: update_history() collect_new_followed()
def init_trakt(cls): config = Configuration.advanced['trakt'] # Build timeout value timeout = (config.get_float('connect_timeout', 6.05), config.get_float('read_timeout', 24)) # Client Trakt.configuration.defaults.client( id= 'c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61', secret= 'bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65') # Application Trakt.configuration.defaults.app(name='trakt (for Plex)', version=PLUGIN_VERSION) # Http Trakt.base_url = (config.get('protocol', 'https') + '://' + config.get('hostname', 'api.trakt.tv')) Trakt.configuration.defaults.http(timeout=timeout) # Configure keep-alive Trakt.http.keep_alive = config.get_boolean('keep_alive', True) # Configure requests adapter Trakt.http.adapter_kwargs = { 'pool_connections': config.get_int('pool_connections', 10), 'pool_maxsize': config.get_int('pool_size', 10), 'max_retries': Retry(total=config.get_int('connect_retries', 3), read=0) } Trakt.http.rebuild() # Bind to events Trakt.on('oauth.refresh', cls.on_trakt_refresh) Trakt.on('oauth.refresh.rejected', cls.on_trakt_refresh_rejected) log.info( 'Configured trakt.py (timeout=%r, base_url=%r, keep_alive=%r, adapter_kwargs=%r)', timeout, Trakt.base_url, Trakt.http.keep_alive, Trakt.http.adapter_kwargs, )
def __init__(self): # Trakt client configuration Trakt.base_url = 'https://api.trakt.tv' Trakt.configuration.defaults.app(**TRAKT_APP) Trakt.configuration.defaults.client(**TRAKT_CLIENT) # Bind trakt events Trakt.on('oauth.refresh', self._on_token_refreshed) self.main_tk = None self.main_win = None self._authorization = None self.username = None self.fullname = None self.playback_ids = []
def test_refresh_token_off(): credentials = TraktCredentials("access", "refresh", "scope", 100) client = Trakt("", "", http_component=TOKEN_REFRESH_HTTP, user=credentials) client.countries.get_countries(type="shows") assert client.user.refresh_token == "refresh" assert client.user.access_token == "access"
def __init__(self, username='******'): credentials = read_credentials() self.username = username self.client_id = credentials['client_id'] self.client_secret = credentials['client_secret'] self.trakt = Trakt.configuration.defaults.client( id=self.client_id, secret=self.client_secret) self.is_authenticating = Condition() # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) self.authorization = self.read_auth() if self.authorization is None: self.authenticate()
def init_trakt(cls): # Client Trakt.configuration.defaults.client( id= 'c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61', secret= 'bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65') # Application Trakt.configuration.defaults.app(name='trakt (for Plex)', version=PLUGIN_VERSION) # Setup request retrying Trakt.http.adapter_kwargs = {'max_retries': Retry(total=3, read=0)} Trakt.http.rebuild() Trakt.on('oauth.token_refreshed', cls.on_token_refreshed)
def __init__(self): # Set trakt app id Trakt.configuration.defaults.app(id=sickrage.app.trakt_app_id) # Set trakt client id/secret Trakt.configuration.defaults.client( id=sickrage.app.trakt_api_key, secret=sickrage.app.trakt_api_secret) # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.oauth(refresh=True) if sickrage.app.config.trakt.oauth_token: Trakt.configuration.defaults.oauth.from_response( sickrage.app.config.trakt.oauth_token)
def __init__(self): # Set trakt app id Trakt.configuration.defaults.app( id=sickrage.srCore.srConfig.TRAKT_APP_ID) # Set trakt client id/secret Trakt.configuration.defaults.client( id=sickrage.srCore.srConfig.TRAKT_API_KEY, secret=sickrage.srCore.srConfig.TRAKT_API_SECRET) # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.oauth(refresh=True) if sickrage.srCore.srConfig.TRAKT_OAUTH_TOKEN: Trakt.configuration.defaults.oauth.from_response( sickrage.srCore.srConfig.TRAKT_OAUTH_TOKEN)
def init_trakt(cls): # Client Trakt.configuration.defaults.client( id='c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61', secret='bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65' ) # Application Trakt.configuration.defaults.app( name='trakt (for Plex)', version=PLUGIN_VERSION ) # Setup request retrying Trakt.http.adapter_kwargs = {'max_retries': Retry(total=3, read=0)} Trakt.http.rebuild() Trakt.on('oauth.token_refreshed', cls.on_token_refreshed)
def test_bad_request_exception(): client = Trakt("", "") http = DefaultHttpComponent( client, requests_dependency=MockRequests({".*": [{}, 400]}) ) with pytest.raises(BadRequest): http.request("...")
def collect_new_followed(): print 'Collection new followed series to trakt.tv' trakt_manager = Trakt() tvshow_manager = TVShowTime() result = tvshow_manager.to_watch() watchlist = [] for s in result['episodes']: print 'Processing ' + s['show']['name'] + '...' show = {"title": s['show']['name'], "ids": {"tvdb": s['show']['id']}} if s['season_number'] == 1 and s['number'] == 1: watchlist.append(show) obj = {"shows": watchlist} trakt_manager.add_to_watchlist(obj) print 'Collected'
def __init__(self, force=False): debug("TRAKT Initializing.") Trakt.configuration.defaults.client(id=self.__client_id, secret=self.__client_secret) Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.oauth(refresh=True) Trakt.configuration.defaults.http(retry=True, timeout=90) from resources.lib.services.Monitor import monitor self.monitor = monitor if not get_setting_as_bool('trakt.enabled'): debug('Trak nieje zapnuty') return self.initialize(force=force)
def init_trakt(): def get_credentials(): password_hash = hashlib.sha1(Prefs['password']) return ( Prefs['username'], password_hash.hexdigest() ) Trakt.configure( # Application api_key='ba5aa61249c02dc5406232da20f6e768f3c82b28', # Version plugin_version=PLUGIN_VERSION, media_center_version=PlexMediaServer.get_version(), # Account credentials=get_credentials )
def test_get_quargs(): client = Trakt("", "") p = Path("a", {}, filters={"query", "genres"}, extended=["metadata"]) assert p.is_valid(client, extended=True, query="xyz", genres=["a", "b"]) _, quargs = p.get_path_and_qargs() expected = {"genres": "a,b", "query": "xyz", "extended": "metadata"} assert quargs == expected
def mk_mock_client(endpoints, client_id="", client_secret="", user=False, paginated=None, **config): return Trakt( client_id, client_secret, http_component=get_mock_http_component(endpoints, paginated=paginated), user=USER if user is False else None, **config, )
def __init__(self): # Set trakt app id Trakt.configuration.defaults.app( id=sickrage.app.config.trakt_app_id ) # Set trakt client id/secret Trakt.configuration.defaults.client( id=sickrage.app.config.trakt_api_key, secret=sickrage.app.config.trakt_api_secret ) # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) Trakt.configuration.defaults.oauth( refresh=True ) if sickrage.app.config.trakt_oauth_token: Trakt.configuration.defaults.oauth.from_response( sickrage.app.config.trakt_oauth_token )
def __init__(self, username='******', mq_=None): credentials = read_credentials() self.username = username self.client_id = credentials['client_id'] self.client_secret = credentials['client_secret'] self.trakt = Trakt.configuration.defaults.client( id=self.client_id, secret=self.client_secret) if mq_ is not None: self.mq_ = mq_ else: self.mq_ = MovieCollection() self.imdb_show_map = {v['link']: k for k, v in self.mq_.imdb_ratings.items()} self.is_authenticating = Condition() # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed) self.authorization = self.read_auth() if self.authorization is None: self.authenticate()
def __init__(self, wf): self.wf = wf # load authorization from settings if 'access_token' in self.wf.settings: self.authorization['access_token'] = self.wf.settings['access_token'] self.authorization['created_at'] = self.wf.settings['created_at'] self.authorization['expires_in'] = self.wf.settings['expires_in'] self.authorization['refresh_token'] = self.wf.settings['refresh_token'] self.authorization['scope'] = self.wf.settings['scope'] self.authorization['token_type'] = self.wf.settings['token_type'] else: self.authorization = {} # bind trakt events Trakt.on('oauth.token_refreshed', self.__on_token_refreshed) # set base url #Trakt.base_url = 'https://api-v2launch.trakt.tv' Trakt.base_url = 'https://api.trakt.tv' # set app defaults Trakt.configuration.defaults.app( id=self.__app_id ) # set client defaults Trakt.configuration.defaults.client( id=self.__client_id, secret=self.__client_secret ) # set oauth defaults Trakt.configuration.defaults.oauth( refresh=True )
def test_filters(): client = Trakt("", "") p = Path("a", {}) with pytest.raises(ArgumentError): p.is_valid(client, genres="genre") p = Path("a", {}, filters={"query", "genres"}) assert p.is_valid(client, query="xyz") with pytest.raises(ArgumentError): p.is_valid(client, query=["xyz", "abc"]) assert p.is_valid(client, genres="genre") assert p.is_valid(client, genres=["abc", "xyz"]) with pytest.raises(ArgumentError): p.is_valid(client, query=[100, "abc"])
def test_optional_args(): client = Trakt("", "") p = Path("calendars/all/shows/new/?start_date/?days", [{"a": str}]) assert p.methods == ["GET"] assert p.args == ["?start_date", "?days"] default_alias = "calendars.all.shows.new" assert p.aliases == [default_alias] assert p.does_match(default_alias) assert not p.does_match(default_alias[1:]) assert p.is_valid(client) assert p.get_path_and_qargs() == ("calendars/all/shows/new", {}) assert p.is_valid(client, start_date="2018-10-10") assert p.get_path_and_qargs() == ("calendars/all/shows/new/2018-10-10", {})
def test_extra_info_return(): client = Trakt("", "") resp_headers = { "X-Pagination-Item-Count": 4, "X-Pagination-Limit": 1, "X-Pagination-Page": 2, "X-Pagination-Page-Count": 3, } http = DefaultHttpComponent( client, requests_dependency=MockRequests({".*": [{"a": "v"}, 200, resp_headers]}), ) res = http.request("abc") assert res.json == {"a": "v"} assert res.original.status_code == 200 assert res.pagination["limit"] == 1 assert res.pagination["page_count"] == 3
def test_extended(): client = Trakt("", "") p = Path("a", {}, extended=["full"]) assert p.is_valid(client) assert p.is_valid(client, extended="full") assert p.is_valid(client, extended=True) with pytest.raises(ArgumentError): p.is_valid(client, extended="meta") p.is_valid(client, extended=True) _, quargs = p.get_path_and_qargs() assert "extended" in quargs and quargs["extended"] == "full" p = Path("a", {}) p.is_valid(client) _, quargs = p.get_path_and_qargs() assert "extended" not in quargs
def test_required_args(): client = Trakt("", "") p = Path("aaa/!b/ccc/?d", [{"a": str}]) assert p.methods == ["GET"] assert p.args == ["!b", "?d"] default_alias = "aaa.ccc" assert p.aliases == [default_alias] assert p.does_match(default_alias) with pytest.raises(ArgumentError): p.is_valid(client) with pytest.raises( ArgumentError): # intentional, assert didn't bind any values p.is_valid(client) assert p.is_valid(client, b=10) assert p.get_path_and_qargs() == ("aaa/10/ccc", {})
def test_refresh_token_on(): client = Trakt("", "", http_component=TOKEN_REFRESH_HTTP, auto_refresh_token=True) # token is not going to expire soon (should not refresh) expire_at = int(time.time()) + 2 * 30 * 24 * 60 * 60 # 60 days client.set_user(TraktCredentials("access", "refresh", "scope", expire_at)) client.countries.get_countries(type="shows") assert client.user.refresh_token == "refresh" assert client.user.access_token == "access" # token is going to expire soon expire_at = int(time.time()) + 15 * 24 * 60 * 60 # 15 days client.set_user(TraktCredentials("access", "refresh", "scope", expire_at)) client.countries.get_countries(type="shows") assert client.user.refresh_token == OAUTH_GET_TOKEN["refresh_token"] assert client.user.access_token == OAUTH_GET_TOKEN["access_token"]
return authorization # Configure Trakt.configuration.defaults.client(id=args.client_id, secret=args.client_secret) if args.reauth: try: os.remove(auth_file) finally: authenticate() exit(0) # Authenticate Trakt.on('oauth.refresh', on_token_refreshed) Trakt.configuration.defaults.oauth.from_response(authenticate(), refresh=True) if Trakt['sync/collection'].movies() is None: print("Error, can't connect to trakt api") exit(2) if args.history: count_items = 20 list = {} for item in Trakt['sync/history'].get(pagination=True, per_page=25): # print() if isinstance(item, objects.episode.Episode): if item.show.title not in list: count_items = count_items - 1 print("%s %s" % (item.show.title, ("S%02dE%02d" % item.pk)))
tvdb = tvdb_api.Tvdb() my_episodes = MyEpisodes( config.get('MyEpisodes', 'Username'), config.get('MyEpisodes', 'Password')) login = my_episodes.login() if(login == False): print "ERROR - Could not login to MyEpisodes" sys.exit(1) my_episodes.get_show_list() trakt = Trakt( config.get('Trakt', 'ClientId'), config.get('Trakt', 'ClientSecret')) print "Requesting Trakt.tv authorization..." print "To authorize access to you trakt.tv account access the following URL in a web browser and copy the authorization code:" print trakt.get_authorize_url() code = raw_input('Paste the authorization code here: ') trakt.authorize(code) for show in my_episodes.show_list: show['name'] = unicodedata.normalize('NFKD', show['name']).encode('ascii','ignore') print "\nProcessing: {}".format(show['name']) try: tvdb_data = tvdb[show['name']] except:
def __init__(self): self.authorization = None # Bind trakt events Trakt.on('oauth.token_refreshed', self.on_token_refreshed)
trakt_manager.add_to_watchlist(obj) print 'Collected' def handler(event, context): parser = ConfigParser.ConfigParser() parser.read('config.ini') trakt_manager = Trakt() if not trakt_manager.is_token_valid(): print 'Your access has been revoked or invalidated, please authenticate again.' else: update_history() collect_new_followed() if __name__ == '__main__': # handler() parser = ConfigParser.ConfigParser() parser.read('config.ini') trakt_manager = Trakt() if not trakt_manager.is_token_valid(): print 'Your access has been revoked or invalidated, please authenticate again.' else: update_history() collect_new_followed()